Comment: | Correction de bugs en pagaille pour les champs membres + gestion dynamique des options pour select et multiple |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
9dbb21bd788315f2c41bd4903f522ac3 |
User & Date: | bohwaz on 2013-01-31 16:25:50 |
Other Links: | manifest | tags |
2013-01-31
| ||
16:33 | Ne pas faire de recherche quand on ne cherche rien + utilisation correcte de trim grumpf check-in: 6fc285dd46 user: bohwaz tags: trunk | |
16:25 | Correction de bugs en pagaille pour les champs membres + gestion dynamique des options pour select et multiple check-in: 9dbb21bd78 user: bohwaz tags: trunk | |
2013-01-30
| ||
17:01 | Affichage du champ correctement plutôt que de manière brute dans les listes check-in: 84bf6d7579 user: bohwaz tags: trunk | |
Modified include/class.champs_membres.php from [2773639a9f] to [65d032fca6].
︙ | ︙ | |||
241 242 243 244 245 246 247 | if ($name == 'email' && $config['type'] != 'email') { throw new UserException('Le champ email ne peut être d\'un type différent de email.'); } if ($name == 'passe' && $config['type'] != 'password') { | | > > > > > | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | if ($name == 'email' && $config['type'] != 'email') { throw new UserException('Le champ email ne peut être d\'un type différent de email.'); } if ($name == 'passe' && $config['type'] != 'password') { throw new UserException('Le champ mot de passe ne peut être d\'un type différent de mot de passe.'); } if (($config['type'] == 'multiple' || $config['type'] == 'select') && empty($config['options'])) { throw new UserException('Le champ "'.$name.'" nécessite de comporter au moins une option possible.'); } if (!array_key_exists('editable', $config)) { $config['editable'] = false; } |
︙ | ︙ | |||
335 336 337 338 339 340 341 | { $db = DB::getInstance(); //$config } /** * Enregistre les changements de champs en base de données | | | | 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 | { $db = DB::getInstance(); //$config } /** * Enregistre les changements de champs en base de données * @param boolean $enable_copy Recopier les anciennes champs dans les nouveaux ? * @return boolean true */ public function save($enable_copy = true) { $db = DB::getInstance(); $config = Config::getInstance(); // Champs à créer $create = array( 'id INTEGER PRIMARY KEY, -- Numéro attribué automatiquement', |
︙ | ︙ | |||
405 406 407 408 409 410 411 | $create = 'CREATE TABLE membres_tmp (' . "\n\t" . implode("\n\t", $create) . "\n);"; $copy = 'INSERT INTO membres_tmp (' . implode(', ', $copy) . ') SELECT ' . implode(', ', $copy) . ' FROM membres;'; $db->exec('PRAGMA foreign_keys = OFF;'); $db->exec('BEGIN;'); $db->exec($create); | | | | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | $create = 'CREATE TABLE membres_tmp (' . "\n\t" . implode("\n\t", $create) . "\n);"; $copy = 'INSERT INTO membres_tmp (' . implode(', ', $copy) . ') SELECT ' . implode(', ', $copy) . ' FROM membres;'; $db->exec('PRAGMA foreign_keys = OFF;'); $db->exec('BEGIN;'); $db->exec($create); if ($enable_copy) { $db->exec($copy); } $db->exec('DROP TABLE IF EXISTS membres;'); $db->exec('ALTER TABLE membres_tmp RENAME TO membres;'); $db->exec('CREATE INDEX membres_id_categorie ON membres (id_categorie);'); // Index $db->exec('END;'); $db->exec('PRAGMA foreign_keys = ON;'); $config->set('champs_membres', $this); $config->save(); return true; } } ?> |
Modified include/class.db.php from [f7a224e087] to [ef3d2d44df].
︙ | ︙ | |||
33 34 35 36 37 38 39 | class DB extends \SQLite3 { static protected $_instance = null; protected $_running_sum = 0.0; | | | | > | > | > > > | < < < < < < < | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | class DB extends \SQLite3 { static protected $_instance = null; protected $_running_sum = 0.0; static public function getInstance($create = false) { return self::$_instance ?: self::$_instance = new DB($create); } private function __clone() { } public function __construct($create = false) { $flags = SQLITE3_OPEN_READWRITE; if ($create) { $flags |= SQLITE3_OPEN_CREATE; } parent::__construct(GARRADIN_DB_FILE, $flags); // Activer les contraintes des foreign keys $this->exec('PRAGMA foreign_keys = ON;'); $this->createFunction('transliterate_to_ascii', array('Garradin\utils', 'transliterateToAscii')); $this->createFunction('base64', 'base64_encode'); $this->createFunction('rank', array($this, 'sql_rank')); $this->createFunction('running_sum', array($this, 'sql_running_sum')); } public function sql_running_sum($data) |
︙ | ︙ |
Modified include/class.membres.php from [8772e65aac] to [f7d52f6be3].
︙ | ︙ | |||
61 62 63 64 65 66 67 | public function login($email, $passe) { if (!filter_var($email, FILTER_VALIDATE_EMAIL)) return false; $db = DB::getInstance(); | | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | public function login($email, $passe) { if (!filter_var($email, FILTER_VALIDATE_EMAIL)) return false; $db = DB::getInstance(); $r = $db->simpleQuerySingle('SELECT *, strftime(\'%s\', date_cotisation) AS date_cotisation FROM membres WHERE email = ? LIMIT 1;', true, trim($email)); if (empty($r)) return false; if (!$this->_checkPassword(trim($passe), $r['passe'])) return false; |
︙ | ︙ | |||
241 242 243 244 245 246 247 | public function _checkFields(&$data, $check_mandatory = true) { $champs = Config::getInstance()->get('champs_membres'); foreach ($champs->getAll() as $key=>$config) { | > > | | < > | > | | > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | public function _checkFields(&$data, $check_mandatory = true) { $champs = Config::getInstance()->get('champs_membres'); foreach ($champs->getAll() as $key=>$config) { if (!isset($data[$key]) || empty($data[$key]) || (!is_array($data[$key]) && !trim($data[$key]))) { if (!empty($config['mandatory']) && $check_mandatory) { throw new UserException('Le champ "' . $config['title'] . '" doit obligatoirement être renseigné.'); } elseif (!empty($config['mandatory'])) { continue; } } if (isset($data[$key])) { if ($config['type'] == 'email' && !filter_var($data[$key], FILTER_VALIDATE_EMAIL)) { throw new UserException('Adresse e-mail invalide dans le champ "' . $config['title'] . '".'); } elseif ($config['type'] == 'url' && !filter_var($data[$key], FILTER_VALIDATE_URL)) { throw new UserException('Adresse URL invalide dans le champ "' . $config['title'] . '".'); } elseif ($config['type'] == 'tel') { $data[$key] = preg_replace('![^\d\+]!', '', $data[$key]); } elseif ($config['type'] == 'country') { $data[$key] = strtoupper(substr($data[$key], 0, 2)); } elseif ($config['type'] == 'checkbox') { $data[$key] = empty($data[$key]) ? 0 : 1; } elseif ($config['type'] == 'number') { if (empty($data[$key])) { $data[$key] = 0; } if (!is_numeric($data[$key])) throw new UserException('Le champ "' . $config['title'] . '" doit contenir un chiffre.'); } elseif ($config['type'] == 'select' && !in_array($data[$key], $config['options'])) { throw new UserException('Le champ "' . $config['title'] . '" ne correspond pas à un des choix proposés.'); } elseif ($config['type'] == 'multiple') { if (empty($data[$key]) || !is_array($data[$key])) { $data[$key] = 0; continue; } $binary = 0; foreach ($data[$key] as $k => $v) { if (array_key_exists($k, $config['options']) && !empty($v)) { $binary |= 0x01 << $k; } } $data[$key] = $binary; } } } if (!empty($data['code_postal'])) { if (!empty($data['pays']) && $data['pays'] == 'FR' && !preg_match('!^\d{5}$!', $data['code_postal'])) { |
︙ | ︙ | |||
408 409 410 411 412 413 414 | } public function get($id) { $db = DB::getInstance(); return $db->simpleQuerySingle('SELECT *, strftime(\'%s\', date_cotisation) AS date_cotisation, | | > | 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | } public function get($id) { $db = DB::getInstance(); return $db->simpleQuerySingle('SELECT *, strftime(\'%s\', date_cotisation) AS date_cotisation, strftime(\'%s\', date_inscription) AS date_inscription, strftime(\'%s\', date_connexion) AS date_connexion FROM membres WHERE id = ? LIMIT 1;', true, (int)$id); } public function delete($ids) { if (!is_array($ids)) { |
︙ | ︙ |
Modified include/data/schema.sql from [97f6a904bb] to [7f4e107406].
︙ | ︙ | |||
11 12 13 14 15 16 17 | CREATE TABLE membres_categories -- Catégories de membres ( id INTEGER PRIMARY KEY, nom TEXT, description TEXT, | | > | < < < < > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | CREATE TABLE membres_categories -- Catégories de membres ( id INTEGER PRIMARY KEY, nom TEXT, description TEXT, montant_cotisation REAL, duree_cotisation INTEGER DEFAULT 12, -- En mois droit_wiki INT DEFAULT 1, droit_membres INT DEFAULT 1, droit_compta INT DEFAULT 1, droit_inscription INT DEFAULT 0, droit_connexion INT DEFAULT 1, droit_config INT DEFAULT 0, cacher INT DEFAULT 0 ); -- Membres de l'asso -- Table dynamique générée par l'application -- voir class.champs_membres.php -- -- WIKI -- CREATE TABLE wiki_pages -- Pages du wiki |
︙ | ︙ |
Modified include/lib.template.php from [841646802c] to [1298a5c695].
︙ | ︙ | |||
35 36 37 38 39 40 41 | $this->assign('is_logged', false); } } $tpl = Template::getInstance(); | < < | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | $this->assign('is_logged', false); } } $tpl = Template::getInstance(); function tpl_csrf_field($params) { $name = utils::CSRF_field_name($params['key']); $value = utils::CSRF_create($params['key']); return '<input type="hidden" name="'.$name.'" value="'.$value.'" />'; } |
︙ | ︙ | |||
430 431 432 433 434 435 436 | elseif ($type == 'multiple') { foreach ($config['options'] as $k=>$v) { $b = 0x01 << (int)$k; $field .= '<label><input type="checkbox" name="' . htmlspecialchars($params['name'], ENT_QUOTES, 'UTF-8') . '[' . (int)$k . ']" value="1" ' | | | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 | elseif ($type == 'multiple') { foreach ($config['options'] as $k=>$v) { $b = 0x01 << (int)$k; $field .= '<label><input type="checkbox" name="' . htmlspecialchars($params['name'], ENT_QUOTES, 'UTF-8') . '[' . (int)$k . ']" value="1" ' . (($value & $b) ? 'checked="checked"' : '') . ' ' . $attributes . '/> ' . htmlspecialchars($v, ENT_QUOTES, 'UTF-8') . '</label><br />'; } } elseif ($type == 'textarea') { $field .= '<textarea ' . $attributes . 'cols="30" rows="5">' . $value . '</textarea>'; } |
︙ | ︙ |
Modified templates/admin/config/membres.tpl from [f5d0be5f0d] to [eb401f2a70].
︙ | ︙ | |||
89 90 91 92 93 94 95 96 97 98 99 100 101 102 | </fieldset> {if !empty($presets)} <fieldset> <legend>Ajouter un champ pré-défini</legend> <p> <select name="preset"> {foreach from=$presets key="name" item="preset"} <option value="{$name|escape}">{$name|escape} — {$preset.title|escape}</option> {/foreach} </select> <input type="submit" name="add" value="Ajouter ce champ à la fiche membre" /> </p> </fieldset> | > | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | </fieldset> {if !empty($presets)} <fieldset> <legend>Ajouter un champ pré-défini</legend> <p> <select name="preset"> <option></option> {foreach from=$presets key="name" item="preset"} <option value="{$name|escape}">{$name|escape} — {$preset.title|escape}</option> {/foreach} </select> <input type="submit" name="add" value="Ajouter ce champ à la fiche membre" /> </p> </fieldset> |
︙ | ︙ | |||
144 145 146 147 148 149 150 | <dt><label>Options disponibles</label></dt> {if $champ.type == 'multiple'} <dd class="help">Attention changer l'ordre des options peut avoir des effets indésirables.</dd> {else} <dd class="help">Attention renommer ou supprimer une option n'affecte pas ce qui a déjà été enregistré dans les fiches des membres.</dd> {/if} | > > | | | | < < < | | | | > | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | <dt><label>Options disponibles</label></dt> {if $champ.type == 'multiple'} <dd class="help">Attention changer l'ordre des options peut avoir des effets indésirables.</dd> {else} <dd class="help">Attention renommer ou supprimer une option n'affecte pas ce qui a déjà été enregistré dans les fiches des membres.</dd> {/if} <dd> <{if $champ.type == 'multiple'}ol{else}ul{/if} class="options"> {if !empty($champ.options)} {foreach from=$champ.options key="key" item="opt"} <li><input type="text" name="champs[{$nom|escape}][options][]" value="{$opt|escape}" size="50" /></li> {/foreach} {/if} {if $champ.type == 'select' || empty($champ.options) || count($champ.options) < 32} <li><input type="text" name="champs[{$nom|escape}][options][]" value="" size="50" /></li> {/if} </dd> {/if} <dt><label for="f_list_row">Numéro de colonne dans la liste des membres</label></dt> <dd class="help">Laisser vide ou indiquer le chiffre zéro pour que ce champ n'apparaisse pas dans la liste des membres. Inscrire un chiffre entre 1 et 10 pour indiquer l'ordre d'affichage du champ dans le tableau de la liste des membres.</dd> <dd><input type="number" id="f_list_row" name="champs[{$nom|escape}][list_row]" min="0" max="10" value="{form_field data=$champs[$nom] name=list_row}" /></dd> </dl> </fieldset> {/foreach} |
︙ | ︙ | |||
285 286 287 288 289 290 291 292 293 294 295 296 297 298 | if (content.style.display.toLowerCase() == 'none') content.style.display = 'block'; else content.style.display = 'none'; return false; }; actions.appendChild(edit); } }()); {/literal} </script> {/if} {include file="admin/_foot.tpl"} | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | if (content.style.display.toLowerCase() == 'none') content.style.display = 'block'; else content.style.display = 'none'; return false; }; actions.appendChild(edit); if (field.querySelector('.options')) { var options = field.querySelectorAll('.options li'); var options_nb = options.length; if (options[0].parentNode.tagName.toLowerCase() == 'ul') { // champ select for (j = 0; j < options_nb; j++) { var remove = document.createElement('input'); remove.type = 'button'; remove.className = 'icn'; remove.value = '-'; remove.title = 'Enlever cette option'; remove.onclick = function (e) { var p = this.parentNode; p.parentNode.removeChild(p); }; options[j].appendChild(remove); } } var add = document.createElement('input'); add.type = 'button'; add.className = 'icn add'; add.value = '+'; add.title = 'Ajouter une option'; add.onclick = function (e) { var p = this.parentNode.parentNode; var options = p.querySelectorAll('li'); var new_option = this.parentNode.cloneNode(true); var btn = new_option.querySelector('input.add'); new_option.getElementsByTagName('input')[0].value = ''; if (options.length >= 30) { new_option.removeChild(btn); } else { btn.onclick = this.onclick; } p.appendChild(new_option); this.parentNode.removeChild(this); }; options[options_nb - 1].appendChild(add); } } }()); {/literal} </script> {/if} {include file="admin/_foot.tpl"} |
Modified templates/admin/membres/fiche.tpl from [ac17437d3f] to [54cbbe580a].
︙ | ︙ | |||
34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <a href="mailto:{$membre[$c]|escape}">{$membre[$c]|escape}</a> {elseif $config.type == 'tel'} <a href="tel:{$membre[$c]|escape}">{$membre[$c]|escape|format_tel}</a> {elseif $config.type == 'country'} {$membre[$c]|get_country_name|escape} {elseif $config.type == 'date' || $config.type == 'datetime'} {$membre[$c]|format_sqlite_date_to_french} {elseif $config.type == 'multiple'} <ul> {foreach from=$config.options key="b" item="name"} {if $membre[$c] & (0x01 << $b)} <li>{$name|escape}</li> {/if} {/foreach} | > > > > | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <a href="mailto:{$membre[$c]|escape}">{$membre[$c]|escape}</a> {elseif $config.type == 'tel'} <a href="tel:{$membre[$c]|escape}">{$membre[$c]|escape|format_tel}</a> {elseif $config.type == 'country'} {$membre[$c]|get_country_name|escape} {elseif $config.type == 'date' || $config.type == 'datetime'} {$membre[$c]|format_sqlite_date_to_french} {elseif $c == 'passe'} Oui {elseif $config.type == 'password'} ******* {elseif $config.type == 'multiple'} <ul> {foreach from=$config.options key="b" item="name"} {if $membre[$c] & (0x01 << $b)} <li>{$name|escape}</li> {/if} {/foreach} |
︙ | ︙ |
Modified www/admin/_inc.php from [b7b4d15400] to [1249a3443e].
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | if (!defined('GARRADIN_LOGIN_PROCESS')) { if (!$membres->isLogged()) { utils::redirect('/admin/login.php'); } $tpl->assign('is_logged', true); $tpl->assign('user', $membres->getLoggedUser()); $user = $membres->getLoggedUser(); $tpl->assign('current', ''); if ($user['droits']['membres'] >= Membres::DROIT_ACCES) { $tpl->assign('nb_membres', $membres->countAllButHidden()); } } ?> | > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | if (!defined('GARRADIN_LOGIN_PROCESS')) { if (!$membres->isLogged()) { utils::redirect('/admin/login.php'); } $tpl->assign('config', Config::getInstance()->getConfig()); $tpl->assign('is_logged', true); $tpl->assign('user', $membres->getLoggedUser()); $user = $membres->getLoggedUser(); $tpl->assign('current', ''); if ($user['droits']['membres'] >= Membres::DROIT_ACCES) { $tpl->assign('nb_membres', $membres->countAllButHidden()); } } ?> |
Modified www/admin/config/membres.php from [314afb4bc4] to [b2a837546b].
︙ | ︙ | |||
88 89 90 91 92 93 94 95 96 97 98 99 100 101 | $config = array( 'type' => utils::post('new_type'), 'title' => utils::post('new_title'), 'editable' => true, 'mandatory' => false, ); $champs->add($new, $config); } $membres->sessionStore('champs_membres', (string) $champs); utils::redirect('/admin/config/membres.php?added'); | > > > > > | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | $config = array( 'type' => utils::post('new_type'), 'title' => utils::post('new_title'), 'editable' => true, 'mandatory' => false, ); if ($config['type'] == 'select' || $config['type'] == 'multiple') { $config['options'] = array('Première option'); } $champs->add($new, $config); } $membres->sessionStore('champs_membres', (string) $champs); utils::redirect('/admin/config/membres.php?added'); |
︙ | ︙ |
Modified www/admin/install.php from [36b266b4e9] to [84f0fd717b].
︙ | ︙ | |||
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | elseif (utils::post('passe_membre') != utils::post('repasse_membre')) { $error = 'La vérification ne correspond pas au mot de passe.'; } else { try { // Configuration de base $config = Config::getInstance(); $config->set('nom_asso', utils::post('nom_asso')); $config->set('adresse_asso', utils::post('adresse_asso')); $config->set('email_asso', utils::post('email_asso')); $config->set('site_asso', utils::post('site_asso')); $config->set('monnaie', '€'); $config->set('pays', 'FR'); $config->set('email_envoi_automatique', utils::post('email_asso')); $config->setVersion(garradin_version()); | > > > > > > > | < < | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | elseif (utils::post('passe_membre') != utils::post('repasse_membre')) { $error = 'La vérification ne correspond pas au mot de passe.'; } else { try { $db = DB::getInstance(true); // Création de la base de données $db->exec('BEGIN;'); $db->exec(file_get_contents(GARRADIN_DB_SCHEMA)); $db->exec('END;'); // Configuration de base $config = Config::getInstance(); $config->set('nom_asso', utils::post('nom_asso')); $config->set('adresse_asso', utils::post('adresse_asso')); $config->set('email_asso', utils::post('email_asso')); $config->set('site_asso', utils::post('site_asso')); $config->set('monnaie', '€'); $config->set('pays', 'FR'); $config->set('email_envoi_automatique', utils::post('email_asso')); $config->setVersion(garradin_version()); $champs = Champs_Membres::importInstall(); $champs->save(false); // Pas de copie car pas de table membres existante // Création catégories $cats = new Membres_Categories; $id = $cats->add(array( 'nom' => 'Membres actifs', 'montant_cotisation' => 10)); $config->set('categorie_membres', $id); |
︙ | ︙ |
Modified www/admin/static/admin.css from [40aa565543] to [d685a74b7c].
︙ | ︙ | |||
153 154 155 156 157 158 159 160 161 162 163 164 165 166 | fieldset dl dd.tip { color: #666; } fieldset dl dd { padding: 0.2em 0.5em 0.2em 1em; } input[type=text], textarea, input[type=password], input[type=email], input[type=url], input[type=tel], select { padding: 0.2em 0.4em; font-family: Sans-serif; min-width: 20em; } | > > > > | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | fieldset dl dd.tip { color: #666; } fieldset dl dd { padding: 0.2em 0.5em 0.2em 1em; } fieldset dl dd ol, fieldset dl dd ul { margin-left: 1.5em; } input[type=text], textarea, input[type=password], input[type=email], input[type=url], input[type=tel], select { padding: 0.2em 0.4em; font-family: Sans-serif; min-width: 20em; } |
︙ | ︙ | |||
180 181 182 183 184 185 186 187 188 189 190 191 192 193 | min-width: 2em; } input[type=submit], input[type=button] { padding: 0.3em; cursor: pointer; } select.large { width: 95%; } select.large optgroup.niveau_1 { background: #333; | > > > > > > > | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | min-width: 2em; } input[type=submit], input[type=button] { padding: 0.3em; cursor: pointer; } input[type=button].icn { font-size: 1.2em; font-weight: bold; padding: 0 0.3em; font-family: "Courier New", Courier, monospace; } select.large { width: 95%; } select.large optgroup.niveau_1 { background: #333; |
︙ | ︙ |