Comment: | Merge with trunk |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | dev |
Files: | files | file ages | folders |
SHA3-256: |
16b2ac559b363c5134e7766e30fc9730 |
User & Date: | bohwaz on 2022-01-02 16:13:53 |
Other Links: | branch diff | manifest | tags |
2022-01-02
| ||
18:28 | Add ID to config_user_fields check-in: dcb692e174 user: bohwaz tags: dev | |
16:13 | Merge with trunk check-in: 16b2ac559b user: bohwaz tags: dev | |
16:04 | Fix checkbox fields: don't allow them to be NULL check-in: 7c23ffae73 user: bohwaz tags: dev | |
2022-01-01
| ||
18:13 | More fixes for a future dark theme check-in: 1333ccbe5d user: bohwaz tags: trunk, stable | |
Modified src/config.dist.php from [1e502eab28] to [af2818b664].
︙ | ︙ | |||
220 221 222 223 224 225 226 227 228 229 230 231 232 233 | * * Si mis à TRUE, alors un bouton sera accessible depuis le menu "Configuration" * pour faire une mise à jour en deux clics. * * Il est conseillé de désactiver cette fonctionnalité si vous ne voulez pas * permettre à un utilisateur de casser l'installation ! * * Défaut : true * * @var bool */ //const ENABLE_UPGRADES = true; | > > > > > | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | * * Si mis à TRUE, alors un bouton sera accessible depuis le menu "Configuration" * pour faire une mise à jour en deux clics. * * Il est conseillé de désactiver cette fonctionnalité si vous ne voulez pas * permettre à un utilisateur de casser l'installation ! * * Si cette constante est désactivée, mais que ENABLE_TECH_DETAILS est activé, * la vérification de nouvelle version se fera quand même, mais plutôt que de proposer * la mise à jour, Garradin proposera de se rendre sur le site officiel pour * télécharger la mise à jour. * * Défaut : true * * @var bool */ //const ENABLE_UPGRADES = true; |
︙ | ︙ | |||
445 446 447 448 449 450 451 | * * %1$s sera remplacé par le chemin du fichier HTML, et %2$s par le chemin du fichier PDF. * * Exemple : chromium --headless --print-to-pdf=%2$s %1$s * * Défaut : null */ | | | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | * * %1$s sera remplacé par le chemin du fichier HTML, et %2$s par le chemin du fichier PDF. * * Exemple : chromium --headless --print-to-pdf=%2$s %1$s * * Défaut : null */ //const PDF_COMMAND = 'wkhtmltopdf -q --print-media-type %s %s'; /** * Clé de licence * * Cette clé permet de débloquer certaines fonctionnalités dans des extensions officielles. * * Pour l'obtenir il faut se créer un compte sur Garradin.eu |
︙ | ︙ |
Modified src/include/lib/Garradin/Accounting/Accounts.php from [9d40c3912e] to [be892e76e5].
︙ | ︙ | |||
81 82 83 84 85 86 87 | } /** * Return only analytical accounts */ public function listAnalytical(): array { | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | } /** * Return only analytical accounts */ public function listAnalytical(): array { return $this->em->DB()->getAssoc($this->em->formatQuery('SELECT id, label FROM @TABLE WHERE id_chart = ? AND type = ? ORDER BY label COLLATE NOCASE;'), $this->chart_id, Account::TYPE_ANALYTICAL); } /** * Return only analytical accounts */ public function listVolunteering(): array { |
︙ | ︙ |
Modified src/include/lib/Garradin/Accounting/Reports.php from [b455a0ddd1] to [9709a17af2].
︙ | ︙ | |||
66 67 68 69 70 71 72 | return implode(' AND ', $where); } /** * Return account sums per year or per account * @param bool $by_year If true will return accounts grouped by year, if false it will return years grouped by account */ | | > > > | | | 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 101 102 103 104 105 106 107 108 109 | return implode(' AND ', $where); } /** * Return account sums per year or per account * @param bool $by_year If true will return accounts grouped by year, if false it will return years grouped by account */ static public function getAnalyticalSums(bool $by_year = false, bool $order_code = false): \Generator { $sql = 'SELECT a.label AS account_label, a.description AS account_description, a.id AS id_account, a.code AS account_code, y.id AS id_year, y.label AS year_label, y.start_date, y.end_date, SUM(l.credit - l.debit) AS sum, SUM(l.credit) AS credit, SUM(l.debit) AS debit, 0 AS total, (SELECT SUM(l2.credit - l2.debit) FROM acc_transactions_lines l2 INNER JOIN acc_transactions t2 ON t2.id = l2.id_transaction INNER JOIN acc_accounts a2 ON a2.id = l2.id_account WHERE a2.position = %d AND l2.id_analytical = l.id_analytical AND t2.id_year = t.id_year) * -1 AS sum_expense, (SELECT SUM(l2.credit - l2.debit) FROM acc_transactions_lines l2 INNER JOIN acc_transactions t2 ON t2.id = l2.id_transaction INNER JOIN acc_accounts a2 ON a2.id = l2.id_account WHERE a2.position = %d AND l2.id_analytical = l.id_analytical AND t2.id_year = t.id_year) AS sum_revenue FROM acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction INNER JOIN acc_accounts a ON a.id = l.id_analytical INNER JOIN acc_years y ON y.id = t.id_year GROUP BY %s ORDER BY %s;'; $order = $order_code ? 'a.code COLLATE NOCASE' : 'a.label COLLATE NOCASE'; if ($by_year) { $group = 'y.id, a.id'; $order = 'y.start_date DESC, ' . $order; } else { $group = 'a.id, y.id'; $order = $order . ', y.id'; } $sql = sprintf($sql, Account::EXPENSE, Account::REVENUE, $group, $order); $current = null; static $sums = ['credit', 'debit', 'sum']; |
︙ | ︙ | |||
130 131 132 133 134 135 136 | yield $current; $current = null; } if (null === $current) { $current = (object) [ 'id' => $by_year ? $row->id_year : $row->id_account, | | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | yield $current; $current = null; } if (null === $current) { $current = (object) [ 'id' => $by_year ? $row->id_year : $row->id_account, 'label' => $by_year ? $row->year_label : ($order_code ? $row->account_code . ' - ' : '') . $row->account_label, 'description' => !$by_year ? $row->account_description : null, 'items' => [] ]; foreach ($sums as $s) { $current->$s = 0; } } $row->label = !$by_year ? $row->year_label : ($order_code ? $row->account_code . ' - ' : '') . $row->account_label; $current->items[] = $row; foreach ($sums as $s) { $current->$s += $row->$s; } } |
︙ | ︙ | |||
273 274 275 276 277 278 279 | if (isset($criterias['compare_year'])) { $where = self::getWhereClause(array_merge($criterias, ['year' => (int)$criterias['compare_year']])); $sql = sprintf($query, $reverse, Line::TABLE, Transaction::TABLE, Account::TABLE, $where, $remove_zero, $order); foreach ($db->iterate($sql) as $row) { if (!isset($out[$row->code])) { $row->sum2 = $row->sum; | | > | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | if (isset($criterias['compare_year'])) { $where = self::getWhereClause(array_merge($criterias, ['year' => (int)$criterias['compare_year']])); $sql = sprintf($query, $reverse, Line::TABLE, Transaction::TABLE, Account::TABLE, $where, $remove_zero, $order); foreach ($db->iterate($sql) as $row) { if (!isset($out[$row->code])) { $row->sum2 = $row->sum; $row->sum = null; $row->id = null; $row->change = null; $out[$row->code] = $row; } else { $out[$row->code]->sum2 = $row->sum; $out[$row->code]->change = ($out[$row->code]->sum - $row->sum); } |
︙ | ︙ | |||
300 301 302 303 304 305 306 | { $accounts = ['asset' => [], 'liability' => []]; $sums = $sums2 = $change = ['asset' => 0, 'liability' => 0]; $position_criteria = ['position' => [Account::ASSET, Account::LIABILITY, Account::ASSET_OR_LIABILITY]]; $list = self::getClosingSumsWithAccounts($criterias + $position_criteria); | < | | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | { $accounts = ['asset' => [], 'liability' => []]; $sums = $sums2 = $change = ['asset' => 0, 'liability' => 0]; $position_criteria = ['position' => [Account::ASSET, Account::LIABILITY, Account::ASSET_OR_LIABILITY]]; $list = self::getClosingSumsWithAccounts($criterias + $position_criteria); foreach ($list as $row) { if ($row->sum == 0 && $row->sum2 == 0) { // Ignore empty accounts continue; } $position = $row->position; if ($position == Account::ASSET_OR_LIABILITY) { |
︙ | ︙ |
Modified src/include/lib/Garradin/Config.php from [bd9053bb32] to [2978dd1e2f].
︙ | ︙ | |||
177 178 179 180 181 182 183 | public function importForm($source = null): void { if (null === $source) { $source = $_POST; } // N'enregistrer les couleurs que si ce ne sont pas les couleurs par défaut | | | | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | public function importForm($source = null): void { if (null === $source) { $source = $_POST; } // N'enregistrer les couleurs que si ce ne sont pas les couleurs par défaut if (isset($source['couleur1'], $source['couleur2']) && ($source['couleur1'] == ADMIN_COLOR1 && $source['couleur2'] == ADMIN_COLOR2)) { $source['couleur1'] = null; $source['couleur2'] = null; } parent::importForm($source); } |
︙ | ︙ | |||
272 273 274 275 276 277 278 279 280 281 282 283 284 285 | } public function hasFile(string $key): bool { return $this->files[$key] ? true : false; } public function setFile(string $key, ?string $value, bool $upload = false): ?File { $f = Files::get(self::FILES[$key]); $files = $this->files; $type = self::FILES_TYPES[$key]; $path = self::FILES[$key]; | > > > > > > > > > > > > > > > > | 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 | } public function hasFile(string $key): bool { return $this->files[$key] ? true : false; } public function updateFiles(): void { $files = $this->files; foreach (self::FILES as $key => $path) { if ($f = Files::get($path)) { $files[$key] = $f->modified->getTimestamp(); } else { $files[$key] = null; } } $this->set('files', $files); } public function setFile(string $key, ?string $value, bool $upload = false): ?File { $f = Files::get(self::FILES[$key]); $files = $this->files; $type = self::FILES_TYPES[$key]; $path = self::FILES[$key]; |
︙ | ︙ |
Modified src/include/lib/Garradin/DB.php from [f878c985d1] to [1efae1a655].
︙ | ︙ | |||
74 75 76 77 78 79 80 | static public function getVersion($db) { $v = (int) $db->querySingle('PRAGMA user_version;'); $v = self::parseVersion($v); if (null === $v) { | > | | > > > > | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | static public function getVersion($db) { $v = (int) $db->querySingle('PRAGMA user_version;'); $v = self::parseVersion($v); if (null === $v) { try { // For legacy version before 1.1.0 $v = $db->querySingle('SELECT valeur FROM config WHERE cle = \'version\';'); } catch (\Exception $e) { throw new \RuntimeException('Cannot find application version', 0, $e); } } return $v ?: null; } static public function parseVersion(int $v): ?string { |
︙ | ︙ |
Modified src/include/lib/Garradin/DynamicList.php from [4a558ce327] to [19f54eeec5].
︙ | ︙ | |||
172 173 174 175 176 177 178 | } // Skip columns that require a certain order AND paginated result if (isset($properties['only_with_order']) && $this->page > 1) { continue; } | < < < < | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | } // Skip columns that require a certain order AND paginated result if (isset($properties['only_with_order']) && $this->page > 1) { continue; } $select = array_key_exists('select', $properties) ? $properties['select'] : $alias; if (null === $select) { $select = 'NULL'; } $columns[] = sprintf('%s AS %s', $select, $alias); |
︙ | ︙ | |||
211 212 213 214 215 216 217 218 219 220 221 222 223 224 | $sql .= sprintf(' LIMIT %d,%d', $start, $this->per_page); } foreach (DB::getInstance()->iterate($sql) as $row) { if ($this->modifier) { call_user_func_array($this->modifier, [&$row]); } yield $row; } } public function loadFromQueryString() { | > > > > > > | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | $sql .= sprintf(' LIMIT %d,%d', $start, $this->per_page); } foreach (DB::getInstance()->iterate($sql) as $row) { if ($this->modifier) { call_user_func_array($this->modifier, [&$row]); } foreach ($this->columns as $key => $config) { if (empty($config['label']) && !$include_hidden) { unset($row->$key); } } yield $row; } } public function loadFromQueryString() { |
︙ | ︙ |
Modified src/include/lib/Garradin/Entities/Accounting/Account.php from [cacd2727a4] to [71842e7b88].
︙ | ︙ | |||
184 185 186 187 188 189 190 | $this->assert(array_key_exists($this->type, self::TYPES_NAMES), 'Type invalide'); $this->assert(array_key_exists($this->position, self::POSITIONS_NAMES), 'Position invalide'); $this->assert($this->user === 0 || $this->user === 1); parent::selfCheck(); } | | > > > > > > > > > > | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | $this->assert(array_key_exists($this->type, self::TYPES_NAMES), 'Type invalide'); $this->assert(array_key_exists($this->position, self::POSITIONS_NAMES), 'Position invalide'); $this->assert($this->user === 0 || $this->user === 1); parent::selfCheck(); } public function listJournal(int $year_id, bool $simple = false, ?DateTimeInterface $start = null, ?DateTimeInterface $end = null) { $db = DB::getInstance(); $columns = self::LIST_COLUMNS; $tables = 'acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction LEFT JOIN acc_accounts b ON b.id = l.id_analytical'; $conditions = sprintf('l.id_account = %d AND t.id_year = %d', $this->id(), $year_id); $sum = 0; $reverse = $simple && self::isReversed($this->type) ? -1 : 1; if ($start) { $conditions .= sprintf(' AND t.date >= %s', $db->quote($start->format('Y-m-d'))); $sum = $this->getSumAtDate($year_id, $start) * $reverse; } if ($end) { $conditions .= sprintf(' AND t.date <= %s', $db->quote($end->format('Y-m-d'))); } if ($simple) { unset($columns['debit']['label'], $columns['credit']['label'], $columns['line_label']); $columns['line_reference']['label'] = 'Réf. paiement'; $columns['change']['select'] = sprintf($columns['change']['select'], $reverse); } else { |
︙ | ︙ | |||
444 445 446 447 448 449 450 | public function getSumAtDate(int $year_id, DateTimeInterface $date, bool $reconciled_only = false): int { $sql = sprintf('SELECT SUM(l.credit) - SUM(l.debit) FROM acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction | | | 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 | public function getSumAtDate(int $year_id, DateTimeInterface $date, bool $reconciled_only = false): int { $sql = sprintf('SELECT SUM(l.credit) - SUM(l.debit) FROM acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction WHERE l.id_account = ? AND t.id_year = ? AND t.date < ? %s;', $reconciled_only ? 'AND l.reconciled = 1' : ''); return (int) DB::getInstance()->firstColumn($sql, $this->id(), $year_id, $date->format('Y-m-d')); } public function importSimpleForm(array $translate_type_position, array $translate_type_codes, ?array $source = null) { if (null === $source) { |
︙ | ︙ |
Modified src/include/lib/Garradin/Entities/Accounting/Transaction.php from [132d3419b2] to [c2407cd421].
︙ | ︙ | |||
818 819 820 821 822 823 824 | $account->targets_string = implode(':', $account->targets); } } return $details; } | | | | 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 | $account->targets_string = implode(':', $account->targets); } } return $details; } public function payOffFrom(int $id): ?\stdClass { $this->_related = EntityManager::findOneById(self::class, $id); if (!$this->_related) { return null; } $this->id_related = $this->_related->id(); $this->label = ($this->_related->type == Transaction::TYPE_DEBT ? 'Règlement de dette : ' : 'Règlement de créance : ') . $this->_related->label; $this->type = $this->_related->type; $out = (object) [ |
︙ | ︙ |
Modified src/include/lib/Garradin/Entities/Files/File.php from [0a495d2483] to [d1459da3c8].
︙ | ︙ | |||
451 452 453 454 455 456 457 458 459 460 461 462 463 464 | static public function create(string $path, string $name, ?string $source_path, ?string $source_content): self { if (!isset($source_path) && !isset($source_content)) { throw new \InvalidArgumentException('Either source path or source content should be set but not both'); } self::validateFileName($name); self::ensureDirectoryExists($path); $finfo = \finfo_open(\FILEINFO_MIME_TYPE); $fullpath = $path . '/' . $name; $file = Files::callStorage('get', $fullpath) ?: new self; $file->set('path', $fullpath); | > | 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | static public function create(string $path, string $name, ?string $source_path, ?string $source_content): self { if (!isset($source_path) && !isset($source_content)) { throw new \InvalidArgumentException('Either source path or source content should be set but not both'); } self::validateFileName($name); self::validatePath($path); self::ensureDirectoryExists($path); $finfo = \finfo_open(\FILEINFO_MIME_TYPE); $fullpath = $path . '/' . $name; $file = Files::callStorage('get', $fullpath) ?: new self; $file->set('path', $fullpath); |
︙ | ︙ | |||
939 940 941 942 943 944 945 | if (preg_match(self::FORBIDDEN_EXTENSIONS, $extension)) { throw new ValidationException('Extension de fichier non autorisée, merci de renommer le fichier avant envoi.'); } } static public function validatePath(string $path): array { | | | | > > | | < < | | | | | 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 | if (preg_match(self::FORBIDDEN_EXTENSIONS, $extension)) { throw new ValidationException('Extension de fichier non autorisée, merci de renommer le fichier avant envoi.'); } } static public function validatePath(string $path): array { $parts = explode('/', $path); if (count($parts) < 1) { throw new ValidationException('Chemin invalide: ' . $path); } $context = array_shift($parts); if (!array_key_exists($context, self::CONTEXTS_NAMES)) { throw new ValidationException('Chemin invalide: ' . $path); } foreach ($parts as $part) { if (substr($part, 0, 1) == '.') { throw new ValidationException('Chemin invalide: ' . $path); } } $name = array_pop($parts); $ref = implode('/', $parts); return [$context, $ref ?: null, $name]; } public function renderFormat(): ?string { if (substr($this->name, -6) == '.skriv') { $format = Render::FORMAT_SKRIV; |
︙ | ︙ |
Modified src/include/lib/Garradin/Entities/Services/Service.php from [1865b4e6a7] to [82c82246f7].
1 2 3 4 5 6 7 8 9 10 11 12 | <?php namespace Garradin\Entities\Services; use Garradin\Config; use Garradin\DynamicList; use Garradin\Entity; use Garradin\ValidationException; use Garradin\Utils; use Garradin\Services\Fees; class Service extends Entity | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php namespace Garradin\Entities\Services; use Garradin\Config; use Garradin\DB; use Garradin\DynamicList; use Garradin\Entity; use Garradin\ValidationException; use Garradin\Utils; use Garradin\Services\Fees; class Service extends Entity |
︙ | ︙ | |||
101 102 103 104 105 106 107 | 'select' => 'su.date', ], ]; $tables = 'services_users su INNER JOIN membres m ON m.id = su.id_user INNER JOIN services s ON s.id = su.id_service | | | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | 'select' => 'su.date', ], ]; $tables = 'services_users su INNER JOIN membres m ON m.id = su.id_user INNER JOIN services s ON s.id = su.id_service LEFT JOIN services_fees sf ON sf.id = su.id_fee INNER JOIN (SELECT id, MAX(date) FROM services_users GROUP BY id_user, id_service) AS su2 ON su2.id = su.id'; $conditions = sprintf('su.id_service = %d AND su.paid = 1 AND (su.expiry_date >= date() OR su.expiry_date IS NULL) AND m.id_category NOT IN (SELECT id FROM users_categories WHERE hidden = 1)', $this->id()); $list = new DynamicList($columns, $tables, $conditions); $list->groupBy('su.id_user'); $list->orderBy('date', true); |
︙ | ︙ | |||
128 129 130 131 132 133 134 | public function expiredUsersList(): DynamicList { $list = $this->paidUsersList(); $conditions = sprintf('su.id_service = %d AND su.expiry_date < date() AND m.id_category NOT IN (SELECT id FROM users_categories WHERE hidden = 1)', $this->id()); $list->setConditions($conditions); return $list; } | | > > > > > > > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | public function expiredUsersList(): DynamicList { $list = $this->paidUsersList(); $conditions = sprintf('su.id_service = %d AND su.expiry_date < date() AND m.id_category NOT IN (SELECT id FROM users_categories WHERE hidden = 1)', $this->id()); $list->setConditions($conditions); return $list; } public function getUsers(bool $paid_only = false) { $where = $paid_only ? 'AND paid = 1' : ''; $id_field = Config::getInstance()->champ_identite; $sql = sprintf('SELECT su.id_user, u.%s FROM services_users su INNER JOIN membres u ON u.id = su.id_user WHERE su.id_service = ? %s;', $id_field, $where); return DB::getInstance()->getAssoc($sql, $this->id()); } } |
Modified src/include/lib/Garradin/Entities/Services/Service_User.php from [70686305f9] to [32122d279b].
︙ | ︙ | |||
41 42 43 44 45 46 47 | protected $_service, $_fee; public function selfCheck(): void { $this->paid = (bool) $this->paid; $this->assert($this->id_service, 'Aucune activité spécifiée'); $this->assert($this->id_user, 'Aucun membre spécifié'); | | > | > > > > > > > > > > > > > > > > > > > | 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 70 71 72 73 74 75 76 | protected $_service, $_fee; public function selfCheck(): void { $this->paid = (bool) $this->paid; $this->assert($this->id_service, 'Aucune activité spécifiée'); $this->assert($this->id_user, 'Aucun membre spécifié'); $this->assert(!$this->isDuplicate(), 'Cette activité a déjà été enregistrée pour ce membre et cette date'); } public function isDuplicate(bool $using_date = true): bool { $params = [ 'id_user' => $this->id_user, 'id_service' => $this->id_service, ]; if ($using_date) { $params['date'] = $this->date->format('Y-m-d'); } $where = array_map(fn($k) => sprintf('%s = ?', $k), array_keys($params)); $where = implode(' AND ', $where); if ($this->exists()) { $where .= sprintf(' AND id != %d', $this->id()); } return DB::getInstance()->test(self::TABLE, $where, array_values($params)); } public function importForm(?array $source = null) { if (null === $source) { $source = $_POST; } |
︙ | ︙ | |||
137 138 139 140 141 142 143 | $transaction->importFromNewForm($source); $transaction->save(); $transaction->linkToUser($this->id_user, $this->id()); return $transaction; } | | > > > > > | | | > | | | > > > > > > > > > | | | | | | | | | | | | | > | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | $transaction->importFromNewForm($source); $transaction->save(); $transaction->linkToUser($this->id_user, $this->id()); return $transaction; } static public function createFromForm(array $users, int $creator_id, bool $from_copy = false, ?array $source = null): self { if (null === $source) { $source = $_POST; } $db = DB::getInstance(); $db->begin(); if (!count($users)) { throw new ValidationException('Aucun membre n\'a été sélectionné.'); } foreach ($users as $id => $name) { $su = new self; $su->date = new \DateTime; $su->importForm($source); $su->id_user = (int) $id; if ($su->id_fee && $su->fee()->id_account && $su->id_user) { $su->expected_amount = $su->fee()->getAmountForUser($su->id_user); } if ($su->isDuplicate($from_copy ? false : true)) { if ($from_copy) { continue; } else { throw new ValidationException(sprintf('%s : Cette activité a déjà été enregistrée pour ce membre et cette date', $name)); } } $su->save(); if ($su->id_fee && $su->fee()->id_account && !empty($source['amount']) && !empty($source['create_payment'])) { try { $su->addPayment($creator_id, $source); } catch (ValidationException $e) { if ($e->getMessage() == 'Il n\'est pas possible de créer ou modifier une écriture dans un exercice clôturé') { throw new ValidationException('Impossible d\'enregistrer l\'inscription : ce tarif d\'activité est lié à un exercice clôturé. Merci de modifier le tarif et choisir un autre exercice.', 0, $e); } else { throw $e; } } } } $db->commit(); return $su; } } |
Modified src/include/lib/Garradin/Files/Storage/SQLite.php from [69084d5de4] to [3cfb59d324].
︙ | ︙ | |||
124 125 126 127 128 129 130 | { return EM::getInstance(File::class)->all('SELECT * FROM @TABLE WHERE parent = ? ORDER BY type DESC, name COLLATE NOCASE ASC;', $path); } static public function listDirectoriesRecursively(string $path): array { $files = []; | | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | { return EM::getInstance(File::class)->all('SELECT * FROM @TABLE WHERE parent = ? ORDER BY type DESC, name COLLATE NOCASE ASC;', $path); } static public function listDirectoriesRecursively(string $path): array { $files = []; $it = DB::getInstance()->iterate('SELECT path FROM files WHERE (parent = ? OR parent LIKE ?) AND type = ? ORDER BY path;', $path, $path . '/%', File::TYPE_DIRECTORY); foreach ($it as $file) { $files[] = substr($file->path, strlen($path) + 1); } return $files; } |
︙ | ︙ |
Modified src/include/lib/Garradin/Sauvegarde.php from [4511e6cf44] to [f6344f677b].
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php namespace Garradin; use Garradin\Users\Session; use Garradin\Files\Files; use KD2\ZipWriter; class Sauvegarde { const NEED_UPGRADE = 0x01 << 2; const NOT_AN_ADMIN = 0x01 << 3; | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?php namespace Garradin; use Garradin\Users\Session; use Garradin\Files\Files; use Garradin\Entities\Files\File; use KD2\ZipWriter; class Sauvegarde { const NEED_UPGRADE = 0x01 << 2; const NOT_AN_ADMIN = 0x01 << 3; |
︙ | ︙ | |||
274 275 276 277 278 279 280 | header('Content-type: application/zip'); header(sprintf('Content-Disposition: attachment; filename="%s"', $name)); $zip = new ZipWriter('php://output'); $zip->setCompression(0); $add_directory = function ($path) use ($zip, &$add_directory) { | > | > > > > > > > | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | header('Content-type: application/zip'); header(sprintf('Content-Disposition: attachment; filename="%s"', $name)); $zip = new ZipWriter('php://output'); $zip->setCompression(0); $add_directory = function ($path) use ($zip, &$add_directory) { try { $list = Files::list($path); } catch (ValidationException $e) { // Ignore invalid paths return; } foreach ($list as $file) { if ($file->type == $file::TYPE_DIRECTORY) { $add_directory($file->path); } else { $zip->add($file->path, null, $file->fullpath()); } } |
︙ | ︙ |
Modified src/include/lib/Garradin/Template.php from [e86659f8b4] to [ba06a7295b].
︙ | ︙ | |||
174 175 176 177 178 179 180 | } return '<p class="block error">' . $this->escape($params['message']) . '</p>'; } protected function widgetIcon(array $params): string { | | | > | > | | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | } return '<p class="block error">' . $this->escape($params['message']) . '</p>'; } protected function widgetIcon(array $params): string { $attributes = array_diff_key($params, ['shape']); $attributes = array_map(fn($v, $k) => sprintf('%s="%s"', $k, $this->escape($v)), $attributes, array_keys($attributes)); $attributes = implode(' ', $attributes); return sprintf('<b class="icn" %s>%s</b>', $attributes, Utils::iconUnicode($params['shape'])); } protected function widgetLink(array $params): string { $href = $params['href']; $label = $params['label']; |
︙ | ︙ | |||
282 283 284 285 286 287 288 | ]); return $out; } protected function formInput(array $params) { | | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | ]); return $out; } protected function formInput(array $params) { static $params_list = ['value', 'default', 'type', 'help', 'label', 'name', 'options', 'source', 'no_size_limit']; // Extract params and keep attributes separated $attributes = array_diff_key($params, array_flip($params_list)); $params = array_intersect_key($params, array_flip($params_list)); extract($params, \EXTR_SKIP); if (!isset($name, $type)) { |
︙ | ︙ | |||
368 369 370 371 372 373 374 | $attributes['data-input'] = 'time'; $attributes['size'] = 8; $attributes['maxlength'] = 5; $attributes['pattern'] = '\d\d?:\d\d?'; } // Create attributes string | | > > > | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | $attributes['data-input'] = 'time'; $attributes['size'] = 8; $attributes['maxlength'] = 5; $attributes['pattern'] = '\d\d?:\d\d?'; } // Create attributes string if (!empty($attributes['required'])) { $attributes['required'] = 'required'; } else { unset($attributes['required']); } if (!empty($attributes['disabled'])) { $attributes['disabled'] = 'disabled'; unset($attributes['required']); } else { unset($attributes['disabled']); |
︙ | ︙ | |||
399 400 401 402 403 404 405 406 407 408 409 410 411 412 | array_walk($attributes_string, function (&$v, $k) { $v = sprintf('%s="%s"', $k, $v); }); $attributes_string = implode(' ', $attributes_string); if ($type == 'select') { $input = sprintf('<select %s>', $attributes_string); foreach ($options as $_key => $_value) { $input .= sprintf('<option value="%s"%s>%s</option>', $_key, $current_value == $_key ? ' selected="selected"' : '', $this->escape($_value)); } | > > > > > > > | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 | array_walk($attributes_string, function (&$v, $k) { $v = sprintf('%s="%s"', $k, $v); }); $attributes_string = implode(' ', $attributes_string); if ($type == 'radio-btn') { $radio = self::formInput(array_merge($params, ['type' => 'radio', 'label' => null, 'help' => null])); $out = sprintf('<dd class="radio-btn">%s <label for="f_%s_%s"><div><h3>%s</h3>%s</div></label> </dd>', $radio, htmlspecialchars($name), htmlspecialchars($value), htmlspecialchars($label), isset($params['help']) ? '<p class="help">' . htmlspecialchars($params['help']) . '</p>' : ''); return $out; } if ($type == 'select') { $input = sprintf('<select %s>', $attributes_string); foreach ($options as $_key => $_value) { $input .= sprintf('<option value="%s"%s>%s</option>', $_key, $current_value == $_key ? ' selected="selected"' : '', $this->escape($_value)); } |
︙ | ︙ | |||
489 490 491 492 493 494 495 | } $out .= '</dd>'; } else { $out = sprintf('<dt>%s%s</dt><dd>%s</dd>', $label, $required_label, $input); | | | 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 | } $out .= '</dd>'; } else { $out = sprintf('<dt>%s%s</dt><dd>%s</dd>', $label, $required_label, $input); if ($type == 'file' && empty($params['no_size_limit'])) { $out .= sprintf('<dd class="help"><small>Taille maximale : %s</small></dd>', Utils::format_bytes(Utils::getMaxUploadSize())); } if (isset($help)) { $out .= sprintf('<dd class="help">%s</dd>', $this->escape($help)); } } |
︙ | ︙ |
Modified src/include/lib/Garradin/Upgrade.php from [45aef26818] to [0e58f34637].
︙ | ︙ | |||
112 113 114 115 116 117 118 | $db->begin(); $db->import(ROOT . '/include/data/1.1.3_migration.sql'); $db->commit(); } if (version_compare($v, '1.1.4', '<')) { // Set config file names | | | | | | 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | $db->begin(); $db->import(ROOT . '/include/data/1.1.3_migration.sql'); $db->commit(); } if (version_compare($v, '1.1.4', '<')) { // Set config file names $file = Files::get(Config::FILES['admin_background']); $db->update('config', ['value' => $file ? Config::FILES['admin_background'] : null], 'key = :key', ['key' => 'admin_background']); $file = Files::get(Config::FILES['admin_homepage']); $db->update('config', ['value' => $file ? Config::FILES['admin_homepage'] : null], 'key = :key', ['key' => 'admin_homepage']); } if (version_compare($v, '1.1.7', '<')) { $db->begin(); $db->import(ROOT . '/include/data/1.1.7_migration.sql'); $db->commit(); } |
︙ | ︙ | |||
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 | foreach ($files as $file) { rename($file, ROOT . '/data/' . basename($file)); } } static public function getLatestVersion(): ?\stdClass { $config = Config::getInstance(); $last = $config->get('last_version_check'); if ($last) { $last = json_decode($last); } // Only check once every two weeks if ($last && $last->time > (time() - 3600 * 24 * 5)) { return $last; } $current_version = garradin_version(); $last = (object) ['time' => time(), 'version' => null]; $config->set('last_version_check', json_encode($last)); $config->save(); $last->version = self::getInstaller()->latest(); | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 323 324 325 326 327 328 329 330 331 332 333 334 | foreach ($files as $file) { rename($file, ROOT . '/data/' . basename($file)); } } static public function getLatestVersion(): ?\stdClass { if (!ENABLE_TECH_DETAILS && !ENABLE_UPGRADES) { return null; } $config = Config::getInstance(); $last = $config->get('last_version_check'); if ($last) { $last = json_decode($last); } // Only check once every two weeks if ($last && $last->time > (time() - 3600 * 24 * 5)) { return $last; } return null; } static public function fetchLatestVersion(): ?\stdClass { if (!ENABLE_TECH_DETAILS && !ENABLE_UPGRADES) { return null; } $config = Config::getInstance(); $last = $config->get('last_version_check'); if ($last) { $last = json_decode($last); } // Only check once every two weeks if ($last && $last->time > (time() - 3600 * 24 * 2)) { return $last; } $current_version = garradin_version(); $last = (object) ['time' => time(), 'version' => null]; $config->set('last_version_check', json_encode($last)); $config->save(); $last->version = self::getInstaller()->latest(); |
︙ | ︙ |
Modified src/include/lib/Garradin/Users/Session.php from [0fa03da91d] to [db4b34e90c].
︙ | ︙ | |||
238 239 240 241 242 243 244 | if (!$user) { return false; } $query = $this->makePasswordRecoveryQuery($user); $message = "Bonjour,\n\nVous avez oublié votre mot de passe ? Pas de panique !\n\n"; | | | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | if (!$user) { return false; } $query = $this->makePasswordRecoveryQuery($user); $message = "Bonjour,\n\nVous avez oublié votre mot de passe ? Pas de panique !\n\n"; $message.= "Il vous suffit de cliquer sur le lien ci-dessous pour modifier votre mot de passe.\n\n"; $message.= ADMIN_URL . 'password.php?c=' . $query; $message.= "\n\nSi vous n'avez pas demandé à recevoir ce message, ignorez-le, votre mot de passe restera inchangé."; return Utils::sendEmail(Utils::EMAIL_CONTEXT_SYSTEM, $user->email, 'Mot de passe perdu ?', $message, $user->id, $user->pgp_key); } protected function fetchUserForPasswordRecovery(int $id): ?\stdClass |
︙ | ︙ |
Modified src/include/lib/Garradin/Utils.php from [04aa6a6cb3] to [f7279d34e4].
︙ | ︙ | |||
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | 'Fri' => 'ven', 'Sat' => 'sam', 'Sun' => 'dim', ]; static public function get_datetime($ts) { if (is_object($ts) && $ts instanceof \DateTimeInterface) { return $ts; } elseif (is_numeric($ts)) { $ts = new \DateTime('@' . $ts); $ts->setTimezone(new \DateTimeZone(date_default_timezone_get())); return $ts; } elseif (strlen($ts) == 10) { return \DateTime::createFromFormat('!Y-m-d', $ts); } elseif (strlen($ts) == 19) { return \DateTime::createFromFormat('Y-m-d H:i:s', $ts); } else { | > > > > > > > | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 'Fri' => 'ven', 'Sat' => 'sam', 'Sun' => 'dim', ]; static public function get_datetime($ts) { if (null === $ts) { return null; } if (is_object($ts) && $ts instanceof \DateTimeInterface) { return $ts; } elseif (is_numeric($ts)) { $ts = new \DateTime('@' . $ts); $ts->setTimezone(new \DateTimeZone(date_default_timezone_get())); return $ts; } elseif (preg_match('!^\d{2}/\d{2}/\d{4}$!', $ts)) { return \DateTime::createFromFormat('!d/m/Y', $ts); } elseif (strlen($ts) == 10) { return \DateTime::createFromFormat('!Y-m-d', $ts); } elseif (strlen($ts) == 19) { return \DateTime::createFromFormat('Y-m-d H:i:s', $ts); } else { |
︙ | ︙ | |||
1074 1075 1076 1077 1078 1079 1080 | case 'prince': $cmd = 'prince -o %2$s %1$s'; break; case 'chromium': $cmd = 'chromium --headless --disable-gpu --run-all-compositor-stages-before-draw --print-to-pdf-no-header --print-to-pdf=%s %s'; break; case 'wkhtmltopdf': | | > > | > | | 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 | case 'prince': $cmd = 'prince -o %2$s %1$s'; break; case 'chromium': $cmd = 'chromium --headless --disable-gpu --run-all-compositor-stages-before-draw --print-to-pdf-no-header --print-to-pdf=%s %s'; break; case 'wkhtmltopdf': $cmd = 'wkhtmltopdf -q --print-media-type %s %s'; break; case 'weasyprint': $cmd = 'weasyprint %1$s %2$s'; break; default: break; } $cmd .= ' 2>&1'; $cmd = sprintf($cmd, escapeshellarg($source), escapeshellarg($target)); $output = shell_exec($cmd); Utils::safe_unlink($source); if (!file_exists($target)) { throw new \RuntimeException('PDF command failed: ' . $output); } return $target; } /** * Integer to A-Z, AA-ZZ, AAA-ZZZ, etc. |
︙ | ︙ |
Modified src/include/lib/Garradin/Web/Web.php from [ce817c70b7] to [d2a80c19dc].
︙ | ︙ | |||
65 66 67 68 69 70 71 | $deleted = array_map(function ($page) { return $page->path; }, $deleted); $db->exec(sprintf('DELETE FROM web_pages WHERE %s;', $db->where('path', $deleted))); } | | > > > | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | $deleted = array_map(function ($page) { return $page->path; }, $deleted); $db->exec(sprintf('DELETE FROM web_pages WHERE %s;', $db->where('path', $deleted))); } $new = array_keys($new); ksort($new); foreach ($new as $path) { $f = Files::get(File::CONTEXT_WEB . '/' . $path . '/index.txt'); if (!$f) { // This is a directory without content, ignore continue; } |
︙ | ︙ |
Modified src/templates/acc/accounts/journal.tpl from [92b1619c26] to [f4432495e8].
︙ | ︙ | |||
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | {linkbutton href="!acc/transactions/new.php?account=%d"|args:$account.id label="Saisir une écriture dans ce compte" shape="plus"} {/if} </aside> <ul> <li{if $simple} class="current"{/if}><a href="?id={$account.id}&simple=1&year={$year.id}">Vue simplifiée</a></li> <li{if !$simple} class="current"{/if}><a href="?id={$account.id}&simple=0&year={$year.id}">Vue comptable</a></li> </ul> </nav> {/if} <form method="post" action="{$admin_url}acc/transactions/actions.php"> {include file="common/dynamic_list_head.tpl" check=$can_edit} {foreach from=$list->iterate() item="line"} <tr> | > > > > > > > > > > > > > > > > > > > > > > > | 61 62 63 64 65 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 | {linkbutton href="!acc/transactions/new.php?account=%d"|args:$account.id label="Saisir une écriture dans ce compte" shape="plus"} {/if} </aside> <ul> <li{if $simple} class="current"{/if}><a href="?id={$account.id}&simple=1&year={$year.id}">Vue simplifiée</a></li> <li{if !$simple} class="current"{/if}><a href="?id={$account.id}&simple=0&year={$year.id}">Vue comptable</a></li> </ul> {if !$filter.start && !$filter.end} <aside> {linkbutton shape="search" href="?start=1" label="Filtrer" onclick="g.toggle('#filterForm', true); this.remove(); return false;"} </aside> {/if} </nav> {/if} <form method="get" action="{$self_url}"{if !$filter.start && !$filter.end} class="hidden"{/if} id="filterForm"> <fieldset> <legend>Filtrer par date</legend> <p> Du {input type="date" name="start" source=$filter default=$year.start_date} au {input type="date" name="end" source=$filter default=$year.end_date} <input type="hidden" name="id" value="{$account.id}" /> <input type="hidden" name="year" value="{$year.id}" /> <input type="hidden" name="simple" value="{$simple}" /> <input type="submit" value="Filtrer" /> </p> </fieldset> </form> <form method="post" action="{$admin_url}acc/transactions/actions.php"> {include file="common/dynamic_list_head.tpl" check=$can_edit} {foreach from=$list->iterate() item="line"} <tr> |
︙ | ︙ | |||
111 112 113 114 115 116 117 | </tbody> <tfoot> <tr> {if $can_edit} <td class="check"><input type="checkbox" value="Tout cocher / décocher" id="f_all2" /><label for="f_all2"></label></td> {/if} {if !$simple}<td></td>{/if} | > | | > > > | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | </tbody> <tfoot> <tr> {if $can_edit} <td class="check"><input type="checkbox" value="Tout cocher / décocher" id="f_all2" /><label for="f_all2"></label></td> {/if} {if !$simple}<td></td>{/if} {if null !== $sum} <td colspan="3">Solde</td> <td class="money">{$sum|raw|money:false}</td> {else} <td colspan="4"></td> {/if} {if !$simple}<td></td>{/if} <td class="actions" colspan="5"> {if $can_edit} <em>Pour les écritures cochées :</em> <input type="hidden" name="from" value="{$self_url}" /> <input type="hidden" name="year" value="{$year.id}" /> {csrf_field key="projects_action"} |
︙ | ︙ |
Modified src/templates/acc/reports/_statement_table.tpl from [29eca66656] to [0f100ae5a3].
︙ | ︙ | |||
13 14 15 16 17 18 19 | </tr> </thead> {/if} <tbody> {foreach from=$accounts item="account"} <tr class="compte{if isset($year2) && !$account.sum} disabled{/if}"> <td class="num"> | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | </tr> </thead> {/if} <tbody> {foreach from=$accounts item="account"} <tr class="compte{if isset($year2) && !$account.sum} disabled{/if}"> <td class="num"> {if !empty($year) && $account.id}<a href="{$admin_url}acc/accounts/journal.php?id={$account.id}&year={$year.id}">{$account.code}</a> {else}{$account.code} {/if} </td> <th>{$account.label}</th> <td class="money">{$account.sum|raw|money:false}</td> {if isset($year2)} <td class="money">{$account.sum2|raw|money:false}</td> <td class="money">{$account.change|raw|money:true:true}</td> {/if} </tr> {/foreach} </tbody> </table> |
Modified src/templates/acc/reports/balance_sheet.tpl from [b458502c4d] to [14beea7ea6].
1 2 3 4 5 6 7 8 9 10 11 12 | {include file="admin/_head.tpl" title="Bilan" current="acc/years"} {include file="acc/reports/_header.tpl" current="balance_sheet" title="Bilan" allow_compare=true} {if $balance.sums.asset != $balance.sums.liability} <p class="alert block"> <strong>Le bilan n'est pas équilibré !</strong><br /> Vérifiez que vous n'avez pas oublié de reporter des soldes depuis le précédent exercice. </p> {/if} <table class="statement"> | < < < < | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | {include file="admin/_head.tpl" title="Bilan" current="acc/years"} {include file="acc/reports/_header.tpl" current="balance_sheet" title="Bilan" allow_compare=true} {if $balance.sums.asset != $balance.sums.liability} <p class="alert block"> <strong>Le bilan n'est pas équilibré !</strong><br /> Vérifiez que vous n'avez pas oublié de reporter des soldes depuis le précédent exercice. </p> {/if} <table class="statement"> <tbody> <tr> <td width="50%"> {include file="acc/reports/_statement_table.tpl" accounts=$balance.accounts.asset caption="Actif"} </td> <td width="50%"> {include file="acc/reports/_statement_table.tpl" accounts=$balance.accounts.liability caption="Passif"} </td> </tr> </tbody> <tfoot> <tr> <td> |
︙ | ︙ |
Modified src/templates/acc/reports/projects.tpl from [c7e14dfc07] to [b9dfb20af8].
︙ | ︙ | |||
11 12 13 14 15 16 17 18 | <li><a href="{$admin_url}acc/years/">Exercices</a></li> {if $session->canAccess($session::SECTION_ACCOUNTING, $session::ACCESS_ADMIN)} <li><a href="{$admin_url}acc/years/new.php">Nouvel exercice</a></li> {/if} <li class="current"><a href="{$admin_url}acc/reports/projects.php">Projets <em>(compta analytique)</em></a></li> </ul> <ul class="sub"> | > > > > > > > > | | | 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 | <li><a href="{$admin_url}acc/years/">Exercices</a></li> {if $session->canAccess($session::SECTION_ACCOUNTING, $session::ACCESS_ADMIN)} <li><a href="{$admin_url}acc/years/new.php">Nouvel exercice</a></li> {/if} <li class="current"><a href="{$admin_url}acc/reports/projects.php">Projets <em>(compta analytique)</em></a></li> </ul> <aside> {if $order_code} {linkbutton href="%s?by_year=%d"|args:$self_url_no_qs,$by_year label="Trier les projets par libellé" shape="menu"} {else} {linkbutton href="%s?by_year=%d&order_code=1"|args:$self_url_no_qs,$by_year label="Trier les projets par code" shape="menu"} {/if} </aside> <ul class="sub"> <li{if !$by_year} class="current"{/if}><a href="{$self_url_no_qs}?order_code={$order_code}">Par projet</a></li> <li{if $by_year} class="current"{/if}><a href="{$self_url_no_qs}?by_year=1&order_code={$order_code}">Par exercice</a></li> </ul> </nav> <div class="year-header"> <h2>{$config.nom_asso} — Projets</h2> <p class="noprint print-btn"> |
︙ | ︙ |
Modified src/templates/acc/transactions/new.tpl from [757fa62572] to [acd090fd81].
︙ | ︙ | |||
19 20 21 22 23 24 25 | {foreach from=$types_details item="type"} <dd class="radio-btn"> {input type="radio" name="type" value=$type.id source=$transaction label=null} <label for="f_type_{$type.id}"> <div> <h3>{$type.label}</h3> {if !empty($type.help)} | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | {foreach from=$types_details item="type"} <dd class="radio-btn"> {input type="radio" name="type" value=$type.id source=$transaction label=null} <label for="f_type_{$type.id}"> <div> <h3>{$type.label}</h3> {if !empty($type.help)} <p class="help">{$type.help}</p> {/if} </div> </label> </dd> {/foreach} </dl> </fieldset> |
︙ | ︙ |
Modified src/templates/admin/_head.tpl from [0c365a5631] to [847f263765].
1 | <!DOCTYPE html> | | | 1 2 3 4 5 6 7 8 9 | <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr" class="{if $dialog}dialog{/if}" data-version="{$version_hash}"> <head> <meta charset="utf-8" /> <meta name="v" content="{$version_hash}" /> <title>{$title}</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="{$admin_url}static/admin.css?{$version_hash}" media="all" /> <script type="text/javascript" src="{$admin_url}static/scripts/global.js?{$version_hash}"></script> |
︙ | ︙ |
Modified src/templates/admin/config/backup/_menu.tpl from [6843e6c837] to [18d2cda81c].
1 2 3 4 5 6 7 | <nav class="tabs"> <ul class="sub"> <li{if $current == 'index'} class="current"{/if}><a href="{$admin_url}config/backup/">Informations</a></li> <li{if $current == 'save'} class="current"{/if}><a href="{$admin_url}config/backup/save.php">Sauvegarder</a></li> <li{if $current == 'restore'} class="current"{/if}><a href="{$admin_url}config/backup/restore.php">Restaurer</a></li> </ul> </nav> | > | 1 2 3 4 5 6 7 8 | <nav class="tabs"> <ul class="sub"> <li{if $current == 'index'} class="current"{/if}><a href="{$admin_url}config/backup/">Informations</a></li> <li{if $current == 'save'} class="current"{/if}><a href="{$admin_url}config/backup/save.php">Sauvegarder</a></li> <li{if $current == 'restore'} class="current"{/if}><a href="{$admin_url}config/backup/restore.php">Restaurer</a></li> <li{if $current == 'documents'} class="current"{/if}><a href="{$admin_url}config/backup/documents.php">Documents</a></li> </ul> </nav> |
Added src/templates/admin/config/backup/documents.tpl version [bfb17f7477].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | {include file="admin/_head.tpl" title="Documents" current="config"} {include file="admin/config/_menu.tpl" current="backup"} {include file="admin/config/backup/_menu.tpl" current="documents"} {if $ok} <p class="confirm block">La restauration a été effectuée.</p> {/if} {if $failed} <p class="alert block">{$failed} fichiers n'ont pas pu être restaurés car ils dépassaient la taille autorisée.</p> {/if} {form_errors} <form method="post" action="{$self_url_no_qs}"> <fieldset> <legend>Téléchargement des documents</legend> <p class="help"> Les documents font {$files_size|size_in_bytes}. </p> {if $files_size > 0} <p class="submit"> {csrf_field key="files_download"} {button type="submit" name="download_files" label="Télécharger une archive ZIP des documents sur mon ordinateur" shape="download" class="main"} </p> {/if} </fieldset> </form> <form method="post" action="{$self_url_no_qs}" id="restoreDocuments" style="display: none;" enctype="multipart/form-data"> <fieldset> <legend>Restaurer les documents</legend> <p class="help"> Sélectionner ici une sauvegarde (archive ZIP) des documents pour les restaurer. </p> <dl> {input type="file" name="file" label="Archive ZIP à restaurer" no_size_limit=true required=true} </dl> <p class="alert block"> Les fichiers existants qui portent le même nom seront écrasés. Les documents existants qui ne figurent pas dans la sauvegarde ne seront pas affectés. </p> <p class="submit"> {csrf_field key="files_restore"} {button type="submit" name="restore" label="Restaurer cette sauvegarde des documents" shape="upload" class="main"} </p> <span class="progress-status"></span> </fieldset> </form> <script type="text/javascript"> g.script('scripts/lib/unzipit.min.js'); g.script('scripts/unzip_restore.js'); </script> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/config/backup/restore.tpl from [79ea96c80e] to [cb8b7573a9].
︙ | ︙ | |||
50 51 52 53 54 55 56 | {input type="checkbox" name="force_import" value="1" label="Ignorer les erreurs, je sais ce que je fait"} </p> {/if} </fieldset> </form> | < < | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | {input type="checkbox" name="force_import" value="1" label="Ignorer les erreurs, je sais ce que je fait"} </p> {/if} </fieldset> </form> <form method="post" action="{$self_url_no_qs}"> <fieldset> <legend>Sauvegardes disponibles</legend> {if empty($list)} <p class="help">Aucune copie de sauvegarde disponible.</p> {else} |
︙ | ︙ | |||
98 99 100 101 102 103 104 | {button type="submit" name="remove" label="Supprimer cette sauvegarde" shape="delete"} </p> {/if} </fieldset> </form> | < < | 96 97 98 99 100 101 102 103 | {button type="submit" name="remove" label="Supprimer cette sauvegarde" shape="delete"} </p> {/if} </fieldset> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/config/backup/save.tpl from [4752a2358e] to [04540ba7a1].
︙ | ︙ | |||
22 23 24 25 26 27 28 | Info : la base de données fait actuellement {$db_size|size_in_bytes}. {if FILE_STORAGE_BACKEND == 'SQLite'} (Dont {$files_size|size_in_bytes} pour les documents.){/if} </p> <p class="submit"> {csrf_field key="backup_download"} {button type="submit" name="download" label="Télécharger une copie de la base de données sur mon ordinateur" shape="download" class="main"} </p> | < < < < < < < < < < < < < | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | Info : la base de données fait actuellement {$db_size|size_in_bytes}. {if FILE_STORAGE_BACKEND == 'SQLite'} (Dont {$files_size|size_in_bytes} pour les documents.){/if} </p> <p class="submit"> {csrf_field key="backup_download"} {button type="submit" name="download" label="Télécharger une copie de la base de données sur mon ordinateur" shape="download" class="main"} </p> </fieldset> </form> <form method="post" action="{$self_url_no_qs}"> <fieldset> |
︙ | ︙ |
Modified src/templates/admin/config/index.tpl from [6e42e917da] to [c89efc01fe].
︙ | ︙ | |||
69 70 71 72 73 74 75 76 77 | <p class="submit"> {csrf_field key="config"} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> {include file="admin/_foot.tpl"} | > > > > > > | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | <p class="submit"> {csrf_field key="config"} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} </p> </form> {if ENABLE_TECH_DETAILS} <script type="text/javascript" async="async"> fetch(g.admin_url + 'config/?check_version'); </script> {/if} {include file="admin/_foot.tpl"} |
Modified src/templates/admin/config/upgrade.tpl from [f0a3b1ba46] to [876a754ddf].
︙ | ︙ | |||
53 54 55 56 57 58 59 | </dl> </details> <dl class="block error"> {input type="checkbox" name="upgrade" value=$version label="Je confirme vouloir procéder à la mise à jour" help="Cette action peut casser votre installation !"} </dl> </fieldset> | | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | </dl> </details> <dl class="block error"> {input type="checkbox" name="upgrade" value=$version label="Je confirme vouloir procéder à la mise à jour" help="Cette action peut casser votre installation !"} </dl> </fieldset> <p class="alert block">N'oubliez pas d'aller {link href="%swiki/?name=Changelog"|args:$website target="_blank" label="lire le journal des changements"} avant d'effectuer la mise à jour !</p> <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="next" label="Effectuer la mise à jour" shape="right" class="main"} </p> {else} <fieldset> <legend>Mise à jour</legend> <dl> {foreach from=$releases key="version" item="release"} {input type="radio" name="download" value=$version label=$version} {if $version == $latest} <dd class="help"> Dernière version stable, conseillée. </dd> {/if} {/foreach} </dl> </fieldset> <p class="alert block">N'oubliez pas d'aller {link href="%swiki/?name=Changelog"|args:$website target="_blank" label="lire le journal des changements"} avant d'effectuer la mise à jour !</p> <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="next" label="Télécharger" shape="right" class="main"} </p> {/if} </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/_list_actions.tpl from [9f86dc3d7a] to [899906bde5].
1 2 3 4 5 6 7 8 9 10 11 12 13 | <tfoot> <tr> {if $session->canAccess($session::SECTION_USERS, $session::ACCESS_ADMIN)}<td class="check"><input type="checkbox" value="Tout cocher / décocher" id="f_all2" /><label for="f_all2"></label></td>{/if} <td class="actions" colspan="{$colspan}"> <em>Pour les membres cochés :</em> {csrf_field key="membres_action"} <select name="action"> <option value="">— Choisir une action à effectuer —</option> <option value="move">Changer de catégorie</option> {if !isset($export) || $export != false} <option value="csv">Exporter en tableau CSV</option> <option value="ods">Exporter en classeur Office</option> {/if} | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <tfoot> <tr> {if $session->canAccess($session::SECTION_USERS, $session::ACCESS_ADMIN)}<td class="check"><input type="checkbox" value="Tout cocher / décocher" id="f_all2" /><label for="f_all2"></label></td>{/if} <td class="actions" colspan="{$colspan}"> <em>Pour les membres cochés :</em> {csrf_field key="membres_action"} <select name="action"> <option value="">— Choisir une action à effectuer —</option> <option value="move">Changer de catégorie</option> {if !isset($export) || $export != false} <option value="csv">Exporter en tableau CSV</option> <option value="ods">Exporter en classeur Office</option> {/if} <option value="delete">Supprimer le membre</option> </select> <noscript> <input type="submit" value="OK" /> </noscript> </td> </tr> </tfoot> |
Modified src/templates/admin/membres/fiche.tpl from [858a55f227] to [56a79db109].
︙ | ︙ | |||
28 29 30 31 32 33 34 | </dd> {/foreach} <dd> {if count($services)} {linkbutton href="!services/user/?id=%d"|args:$membre.id label="Liste des inscriptions aux activités" shape="menu"} {/if} {if $session->canAccess($session::SECTION_USERS, $session::ACCESS_WRITE)} | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | </dd> {/foreach} <dd> {if count($services)} {linkbutton href="!services/user/?id=%d"|args:$membre.id label="Liste des inscriptions aux activités" shape="menu"} {/if} {if $session->canAccess($session::SECTION_USERS, $session::ACCESS_WRITE)} {linkbutton href="!services/user/subscribe.php?user=%d"|args:$membre.id label="Inscrire à une activité" shape="plus"} {/if} </dd> {if count($services)} <dd> {linkbutton shape="alert" label="Liste des rappels envoyés" href="!services/reminders/user.php?id=%d"|args:$membre.id} </dd> {/if} |
︙ | ︙ |
Modified src/templates/services/user/_service_user_form.tpl from [10a2edc910] to [75a8977fdd].
1 2 3 4 | <?php assert(isset($create) && is_bool($create)); assert(isset($has_past_services) && is_bool($has_past_services)); assert(isset($current_only) && is_bool($current_only)); | < | 1 2 3 4 5 6 7 8 9 10 11 | <?php assert(isset($create) && is_bool($create)); assert(isset($has_past_services) && is_bool($has_past_services)); assert(isset($current_only) && is_bool($current_only)); assert(isset($form_url) && is_string($form_url)); assert(isset($today) && $today instanceof \DateTimeInterface); assert($create === false || isset($account_targets)); assert(isset($grouped_services) && is_array($grouped_services)); ?> <form method="post" action="{$self_url}" data-focus="1" data-create="{$create|escape:json}"> |
︙ | ︙ | |||
20 21 22 23 24 25 26 | </nav> {/if} <fieldset> <legend>Inscrire un membre à une activité</legend> <dl> | > | > > | > > > > > > > > > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | </nav> {/if} <fieldset> <legend>Inscrire un membre à une activité</legend> <dl> {if $create && $users} <dt>Membres inscrits</dt> {if count($users) <= 10} {foreach from=$users key="id" item="name"} <dd>{$name}<input type="hidden" name="users[{$id}]" value="{$name}" /></dd> {/foreach} {else} <dd>{$users|count} membres sélectionnés</dd> {/if} {elseif $create && $copy_service} <dt>Recopier depuis l'activité</dt> <dd><strong>{$copy_service.label}</strong><input type="hidden" name="copy_service" value="{$copy_service.id}" /></dd> <dd><em>{if $copy_service_only_paid}(seulement les inscriptions marquées comme payées){else}(toutes les inscriptions){/if}</em><input type="hidden" name="copy_service_only_paid" value="{$copy_service_only_paid}" /></dd> {/if} <dt><label for="f_service_ID">Activité</label> <b>(obligatoire)</b></dt> {foreach from=$grouped_services item="service"} <dd class="radio-btn"> {input type="radio" name="id_service" value=$service.id data-duration=$service.duration data-expiry=$service.expiry_date|date_short label=null source=$service_user} <label for="f_id_service_{$service.id}"> |
︙ | ︙ | |||
65 66 67 68 69 70 71 | {foreach from=$service.fees key="service_id" item="fee"} <dd class="radio-btn"> {input type="radio" name="id_fee" value=$fee.id data-user-amount=$fee.user_amount data-account=$fee.id_account data-year=$fee.id_year label=null source=$service_user } <label for="f_id_fee_{$fee.id}"> <div> <h3>{$fee.label}</h3> <p> | < < | > > > > | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | {foreach from=$service.fees key="service_id" item="fee"} <dd class="radio-btn"> {input type="radio" name="id_fee" value=$fee.id data-user-amount=$fee.user_amount data-account=$fee.id_account data-year=$fee.id_year label=null source=$service_user } <label for="f_id_fee_{$fee.id}"> <div> <h3>{$fee.label}</h3> <p> {if $fee.user_amount && $fee.formula} <strong>{$fee.user_amount|raw|money_currency}</strong> (montant calculé) {elseif $fee.formula} montant calculé, variable selon les membres {elseif $fee.user_amount} <strong>{$fee.user_amount|raw|money_currency}</strong> {else} prix libre ou gratuit {/if} </p> {if $fee.description} <p class="help"> {$fee.description|escape|nl2br} </p> {/if} |
︙ | ︙ | |||
118 119 120 121 122 123 124 | </fieldset> {/if} <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} | | | 131 132 133 134 135 136 137 138 139 140 141 142 143 | </fieldset> {/if} <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} {if $create && $users && count($users) == 1} {button type="submit" name="save_and_add_payment" class="accounting" label="Enregistrer et ajouter un autre règlement" shape="plus"} {/if} </p> </form> |
Modified src/templates/services/user/add.tpl from [e38a83f3e8] to [9109d7951b].
1 2 3 4 5 6 | {include file="admin/_head.tpl" title="Inscrire à une activité" current="membres/services"} {include file="services/_nav.tpl" current="save" fee=null service=null} {form_errors} | < | | > > > > | > > > > > > > > > > > > < | > > > > > > | < > > > | > | 1 2 3 4 5 6 7 8 9 10 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 40 41 42 43 44 45 46 47 48 49 50 51 | {include file="admin/_head.tpl" title="Inscrire à une activité" current="membres/services"} {include file="services/_nav.tpl" current="save" fee=null service=null} {form_errors} <form method="post" action="subscribe.php" data-focus="button"> <fieldset> <legend>Inscrire à une activité</legend> <dl> {input type="radio-btn" name="choice" value="1" label="Sélectionner des membres" default=1} {input type="radio-btn" name="choice" value="2" label="Recopier depuis une activité" help="Utile si vous avez une cotisation par année civile par exemple : copie les membres inscrits l'année précédente dans la nouvelle année."} </dl> </fieldset> <fieldset class="c1"> <legend>Inscrire des membres</legend> <dl> {input type="list" name="users" required=true label="Membres à inscrire" target="membres/selector.php" multiple=true} </dl> </fieldset> <fieldset class="c2"> <legend>Recopier depuis une activité</legend> <dl> {input type="select" name="copy_service" label="Activité à recopier" options=$services required=true default=0} {input type="checkbox" name="copy_service_only_paid" value="1" label="Ne recopier que les membres dont l'inscription est payée"} </dl> </fieldset> <p class="submit"> {button type="submit" name="next" label="Continuer" shape="right" class="main"} </p> </form> <script type="text/javascript"> {literal} function selectChoice() { let choice = $('#f_choice_1').form.choice.value; g.toggle('.c1', choice == 1); g.toggle('.c2', choice == 2); } selectChoice(); $('#f_choice_1').onchange = selectChoice; $('#f_choice_2').onchange = selectChoice; {/literal} </script> {include file="admin/_foot.tpl"} |
Modified src/templates/services/user/index.tpl from [0bde5bd459] to [43943e4257].
1 2 3 4 | {include file="admin/_head.tpl" title="%s — Inscriptions aux activités et cotisations"|args:$user.identite current="membres/services"} <p> {linkbutton href="!membres/fiche.php?id=%d"|args:$user.id label="Retour à la fiche membre" shape="user"} | | | 1 2 3 4 5 6 7 8 9 10 11 12 | {include file="admin/_head.tpl" title="%s — Inscriptions aux activités et cotisations"|args:$user.identite current="membres/services"} <p> {linkbutton href="!membres/fiche.php?id=%d"|args:$user.id label="Retour à la fiche membre" shape="user"} {linkbutton href="!services/user/subscribe.php?user=%d"|args:$user.id label="Inscrire à une activité" shape="plus"} </p> {form_errors} <dl class="cotisation"> <dt>Statut des inscriptions</dt> {foreach from=$services item="service"} |
︙ | ︙ |
Added src/templates/services/user/subscribe.tpl version [8f9805b504].
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | {include file="admin/_head.tpl" title="Inscrire à une activité" current="membres/services"} {include file="services/_nav.tpl" current="save" fee=null service=null} {form_errors} {include file="services/user/_service_user_form.tpl" create=true} {include file="admin/_foot.tpl"} |
Modified src/templates/web/_attach.tpl from [dbe6b7661f] to [1e5c124ad7].
︙ | ︙ | |||
27 28 29 30 31 32 33 | <dt>Alignement :</dt> <dd class="align"> <input type="button" name="left" value="À gauche" /> <input type="button" name="center" value="Au centre" /> <input type="button" name="right" value="À droite" /> </dd> <dd class="cancel"> | | | 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <dt>Alignement :</dt> <dd class="align"> <input type="button" name="left" value="À gauche" /> <input type="button" name="center" value="Au centre" /> <input type="button" name="right" value="À droite" /> </dd> <dd class="cancel"> <button type="reset">Annuler</button> </dd> </dl> </fieldset> </form> {if !empty($images)} <ul class="gallery"> |
︙ | ︙ |
Modified src/www/admin/acc/accounts/journal.php from [da00ba6416] to [af0fa51c71].
︙ | ︙ | |||
47 48 49 50 51 52 53 | $simple = qg('simple'); // Use simplified view for favourite accounts if (null === $simple) { $simple = (bool) $account->type; } | > > > > | > > > | > > | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | $simple = qg('simple'); // Use simplified view for favourite accounts if (null === $simple) { $simple = (bool) $account->type; } $filter = new \stdClass; $filter->start = Utils::get_datetime(qg('start')); $filter->end = Utils::get_datetime(qg('end')); $list = $account->listJournal($year_id, $simple, $filter->start, $filter->end); $list->setTitle(sprintf('Journal - %s - %s', $account->code, $account->label)); $list->loadFromQueryString(); $sum = null; if (!$filter->start && !$filter->end) { $sum = $account->getSum($year_id, $simple); } $tpl->assign(compact('simple', 'year', 'account', 'list', 'sum', 'can_edit', 'filter')); $tpl->display('acc/accounts/journal.tpl'); |
Modified src/www/admin/acc/reports/projects.php from [a9751b3536] to [2489bf7ddc].
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php namespace Garradin; use Garradin\Accounting\Accounts; use Garradin\Accounting\Reports; use Garradin\Entities\Accounting\Account; require_once __DIR__ . '/../_inc.php'; $session->requireAccess($session::SECTION_ACCOUNTING, $session::ACCESS_READ); $by_year = (bool)qg('by_year'); | > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?php namespace Garradin; use Garradin\Accounting\Accounts; use Garradin\Accounting\Reports; use Garradin\Entities\Accounting\Account; require_once __DIR__ . '/../_inc.php'; $session->requireAccess($session::SECTION_ACCOUNTING, $session::ACCESS_READ); $by_year = (bool)qg('by_year'); $order_code = (bool)qg('order_code'); $tpl->assign(compact('by_year', 'order_code')); $tpl->assign('list', Reports::getAnalyticalSums($by_year, $order_code)); $tpl->assign('analytical_type', Account::TYPE_ANALYTICAL); $tpl->assign('analytical_accounts_count', CURRENT_YEAR_ID ? $current_year->accounts()->countByType(Account::TYPE_ANALYTICAL) : null); $tpl->display('acc/reports/projects.tpl'); |
Modified src/www/admin/acc/transactions/new.php from [c612c4dc3a] to [0cd4c89e75].
︙ | ︙ | |||
63 64 65 66 67 68 69 | $account = $accounts::get($id); if (!$account || $account->id_chart != $current_year->id_chart) { throw new UserException('Ce compte ne correspond pas à l\'exercice comptable ou n\'existe pas'); } $transaction->type = Transaction::getTypeFromAccountType($account->type); | > | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | $account = $accounts::get($id); if (!$account || $account->id_chart != $current_year->id_chart) { throw new UserException('Ce compte ne correspond pas à l\'exercice comptable ou n\'existe pas'); } $transaction->type = Transaction::getTypeFromAccountType($account->type); $index = $transaction->type == Transaction::TYPE_DEBT || $transaction->type == Transaction::TYPE_CREDIT ? 1 : 0; $key = sprintf('account_%d_%d', $transaction->type, $index); if (!isset($_POST[$key])) { $lines[0]['account'] = $_POST[$key] = [$account->id => sprintf('%s — %s', $account->code, $account->label)]; } } elseif (!empty($_POST['lines']) && is_array($_POST['lines'])) { $lines = Utils::array_transpose($_POST['lines']); |
︙ | ︙ |
Added src/www/admin/config/backup/documents.php version [185acbc75a].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 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 40 41 42 43 44 45 46 47 48 49 50 51 52 | <?php namespace Garradin; use Garradin\Web\Web; use Garradin\Files\Files; use Garradin\Entities\Files\File; require_once __DIR__ . '/../_inc.php'; $form->runIf('restore', function () { try { // Decompress (inflate) raw data if (isset($_FILES['file1']['tmp_name']) && f('compressed')) { $f = $_FILES['file1']['tmp_name']; file_put_contents($f, gzinflate(file_get_contents($f), 1024*1024*1024)); } File::upload(Utils::dirname(f('target')), 'file1'); } catch (UserException $e) { die(json_encode(['success' => false, 'error' => f('target') . ': '. $e->getMessage()])); } die(json_encode(['success' => true, 'error' => null])); }, 'files_restore'); // Download all files as ZIP $form->runIf('download_files', function () { (new Sauvegarde)->dumpFilesZip(); exit; }, 'files_download'); $ok = qg('ok') !== null; $failed = (int) qg('failed'); if ($ok) { // Reset $config->updateFiles(); $config->save(); $tpl->assign(compact('config')); Web::sync(true); Static_Cache::clean(0); } $files_size = Files::getUsedQuota(); $tpl->assign(compact('files_size', 'failed', 'ok')); $tpl->display('admin/config/backup/documents.tpl'); |
Modified src/www/admin/config/backup/save.php from [0defc760cc] to [9f5c67bf3b].
︙ | ︙ | |||
9 10 11 12 13 14 15 | // Download database $form->runIf('download', function () use ($s) { $s->dump(); exit; }, 'backup_download'); | < < < < < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // Download database $form->runIf('download', function () use ($s) { $s->dump(); exit; }, 'backup_download'); // Create local backup $form->runIf('create', function () use ($s) { $s->create(); }, 'backup_create', Utils::getSelfURI(['ok' => 'create'])); $form->runIf('config', function () { if (!ENABLE_AUTOMATIC_BACKUPS) { |
︙ | ︙ | |||
44 45 46 47 48 49 50 | $config = Config::getInstance(); $config->set('frequence_sauvegardes', $frequency); $config->set('nombre_sauvegardes', $number); $config->save(); }, 'backup_config', Utils::getSelfURI(['ok' => 'config'])); $db_size = $s->getDBSize(); | | | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | $config = Config::getInstance(); $config->set('frequence_sauvegardes', $frequency); $config->set('nombre_sauvegardes', $number); $config->save(); }, 'backup_config', Utils::getSelfURI(['ok' => 'config'])); $db_size = $s->getDBSize(); $files_size = (FILE_STORAGE_BACKEND == 'SQLite') ? Files::getUsedQuota() : null; $ok = qg('ok'); // return message $tpl->assign(compact('ok', 'db_size', 'files_size')); $tpl->display('admin/config/backup/save.tpl'); |
Modified src/www/admin/config/index.php from [a6385e7542] to [746271d6a0].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php namespace Garradin; use Garradin\Users\Categories; use Garradin\Files\Files; use Garradin\Entities\Files\File; require_once __DIR__ . '/_inc.php'; $config = Config::getInstance(); $form->runIf('save', function () use ($config) { $config->importForm(); $config->save(); }, 'config', Utils::getSelfURI(['ok' => ''])); | > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?php namespace Garradin; use Garradin\Users\Categories; use Garradin\Files\Files; use Garradin\Entities\Files\File; require_once __DIR__ . '/_inc.php'; if (qg('check_version') !== null) { echo json_encode(Upgrade::fetchLatestVersion()); exit; } $config = Config::getInstance(); $form->runIf('save', function () use ($config) { $config->importForm(); $config->save(); }, 'config', Utils::getSelfURI(['ok' => ''])); $latest = Upgrade::getLatestVersion(); if (null !== $latest) { $latest = $latest->version; } $tpl->assign([ 'garradin_version' => garradin_version() . ' [' . (garradin_manifest() ?: 'release') . ']', |
︙ | ︙ |
Modified src/www/admin/config/upgrade.php from [423a4f1508] to [da1b2c3223].
︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 | $form->runIf('upgrade', function () use ($i) { $url = ADMIN_URL . 'upgrade.php'; $i->upgrade(f('upgrade')); header('Location: ' . $url); exit; }, $csrf_key); $tpl->assign(compact('releases', 'latest', 'csrf_key')); $tpl->display('admin/config/upgrade.tpl'); | > | 39 40 41 42 43 44 45 46 47 48 | $form->runIf('upgrade', function () use ($i) { $url = ADMIN_URL . 'upgrade.php'; $i->upgrade(f('upgrade')); header('Location: ' . $url); exit; }, $csrf_key); $tpl->assign('website', WEBSITE); $tpl->assign(compact('releases', 'latest', 'csrf_key')); $tpl->display('admin/config/upgrade.tpl'); |
Modified src/www/admin/manifest.php from [97a146fba4] to [1e14f72078].
1 2 3 4 5 6 7 | <?php namespace Garradin; const LOGIN_PROCESS = true; require_once __DIR__ . '/_inc.php'; $manifest = [ | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?php namespace Garradin; const LOGIN_PROCESS = true; require_once __DIR__ . '/_inc.php'; $manifest = [ 'background_color' => $config->couleur2 ?? ADMIN_COLOR2, 'theme_color' => $config->couleur1 ?? ADMIN_COLOR1, 'description' => 'Gestion de l\'association', 'display' => 'standalone', 'name' => $config->nom_asso, 'start_url' => ADMIN_URL, 'icons' => [ [ 'sizes' => '32x32', 'src' => $config->fileURL('favicon'), 'type' => 'image/png', |
︙ | ︙ |
Modified src/www/admin/plugin.php from [306b922a17] to [3da4ea03c5].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; $page = qg('_u') ?: 'index.php'; $plugin = new Plugin(qg('_p')); define('Garradin\PLUGIN_ROOT', $plugin->path()); define('Garradin\PLUGIN_URL', ADMIN_URL . 'plugin/' . $plugin->id() . '/'); define('Garradin\PLUGIN_QSP', '?'); $tpl->assign('plugin', $plugin->getInfos()); $tpl->assign('plugin_url', PLUGIN_URL); $tpl->assign('plugin_root', PLUGIN_ROOT); $plugin->call('admin/' . $page); | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; $page = qg('_u') ?: 'index.php'; if (substr($page, -1) == '/') { $page .= 'index.php'; } $plugin = new Plugin(qg('_p')); define('Garradin\PLUGIN_ROOT', $plugin->path()); define('Garradin\PLUGIN_URL', ADMIN_URL . 'plugin/' . $plugin->id() . '/'); define('Garradin\PLUGIN_QSP', '?'); $tpl->assign('plugin', $plugin->getInfos()); $tpl->assign('plugin_url', PLUGIN_URL); $tpl->assign('plugin_root', PLUGIN_ROOT); $plugin->call('admin/' . $page); |
Modified src/www/admin/services/user/_form.php from [355c6ae19e] to [f5cd3da56d].
1 2 3 4 5 6 7 8 9 10 11 | <?php namespace Garradin; use Garradin\Services\Services; if (!defined('\Garradin\ROOT')) { die(); } | | > > > > > > | | > | > | 1 2 3 4 5 6 7 8 9 10 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 40 41 42 | <?php namespace Garradin; use Garradin\Services\Services; if (!defined('\Garradin\ROOT')) { die(); } assert(isset($tpl, $form_url, $create)); $current_only = !qg('past_services'); // If there is only one user selected we can calculate the amount $single_user_id = isset($users) && count($users) == 1 ? key($users) : null; $copy_service ??= null; $copy_service_only_paid ??= null; $users ??= null; $grouped_services = Services::listGroupedWithFees($single_user_id, $current_only); if (!count($grouped_services)) { $current_only = false; $grouped_services = Services::listGroupedWithFees($single_user_id, $current_only); } if (!isset($count_all)) { $count_all = Services::count(); } $has_past_services = count($grouped_services) != $count_all; $today = new \DateTime; $tpl->assign([ 'custom_js' => ['service_form.js'], ]); $tpl->assign(compact('form_url', 'today', 'grouped_services', 'current_only', 'has_past_services', 'create', 'copy_service', 'copy_service_only_paid', 'users')); |
Modified src/www/admin/services/user/add.php from [614b57c4f4] to [97a4cefe05].
1 2 3 4 | <?php namespace Garradin; use Garradin\Services\Services; | < < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php namespace Garradin; use Garradin\Services\Services; require_once __DIR__ . '/../_inc.php'; $session->requireAccess($session::SECTION_USERS, $session::ACCESS_WRITE); // This controller allows to either select a user if none has been provided in the query string // or subscribe a user to an activity (create a new Service_User entity) // If $user_id is null then the form is just a select to choose a user $count_all = Services::count(); if (!$count_all) { Utils::redirect(ADMIN_URL . 'services/?CREATE'); } $services = array_merge([0 => '-- Sélectionner une activité'], Services::listAssoc()); $tpl->assign(compact('services')); $tpl->display('services/user/add.tpl'); |
Modified src/www/admin/services/user/edit.php from [b0b3db3c77] to [f09c2d97e9].
︙ | ︙ | |||
10 11 12 13 14 15 16 | $su = Services_User::get((int) qg('id')); if (!$su) { throw new UserException("Cette inscription n'existe pas"); } $csrf_key = 'su_edit_' . $su->id(); | < | > | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | $su = Services_User::get((int) qg('id')); if (!$su) { throw new UserException("Cette inscription n'existe pas"); } $csrf_key = 'su_edit_' . $su->id(); $users = [$su->id_user => (new Membres)->getNom($su->id_user)]; $form_url = sprintf('edit.php?id=%d&', $su->id()); $create = false; require __DIR__ . '/_form.php'; $form->runIf('save', function () use ($su) { $su->importForm(); $su->save(); }, $csrf_key, ADMIN_URL . 'services/user/?id=' . $su->id_user); $service_user = $su; $tpl->assign(compact('csrf_key', 'service_user')); $tpl->display('services/user/edit.tpl'); |
Added src/www/admin/services/user/subscribe.php version [92ce32bd63].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 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 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 70 71 72 73 74 75 76 | <?php namespace Garradin; use Garradin\Services\Services; use Garradin\Entities\Services\Service_User; use Garradin\Entities\Accounting\Account; use Garradin\Entities\Accounting\Transaction; require_once __DIR__ . '/../_inc.php'; $session->requireAccess($session::SECTION_USERS, $session::ACCESS_WRITE); // This controller allows to either select a user if none has been provided in the query string // or subscribe a user to an activity (create a new Service_User entity) // If $user_id is null then the form is just a select to choose a user $count_all = Services::count(); if (!$count_all) { Utils::redirect(ADMIN_URL . 'services/?CREATE'); } $users = null; $copy_service = null; $copy_service_only_paid = null; if (qg('user') && ($name = (new Membres)->getNom((int)qg('user')))) { $users = [(int)qg('user') => $name]; } elseif (f('users') && is_array(f('users')) && count(f('users'))) { $users = f('users'); $users = array_filter($users, 'intval', \ARRAY_FILTER_USE_KEY); } elseif (f('copy_service') && $copy_service = Services::get((int)f('copy_service'))) { $copy_service_only_paid = (bool) f('copy_service_only_paid'); } else { throw new UserException('Aucun membre n\'a été sélectionné'); } $form_url = '?'; $csrf_key = 'service_save'; $create = true; // Only load the form if a user has been selected require __DIR__ . '/_form.php'; $form->runIf(f('save') || f('save_and_add_payment'), function () use ($session, $users, $copy_service, $copy_service_only_paid) { if ($copy_service) { $users = $copy_service->getUsers($copy_service_only_paid); } $su = Service_User::createFromForm($users, $session->getUser()->id, $copy_service ? true : false); if (count($users) > 1) { $url = ADMIN_URL . 'services/details.php?id=' . $su->id_service; } elseif (f('save_and_add_payment')) { $url = ADMIN_URL . 'services/user/payment.php?id=' . $su->id; } else { $url = ADMIN_URL . 'services/user/?id=' . $su->id_user; } Utils::redirect($url); }, $csrf_key); $types_details = Transaction::getTypesDetails(); $account_targets = $types_details[Transaction::TYPE_REVENUE]->accounts[1]->targets_string; $service_user = null; $tpl->assign(compact('csrf_key', 'users', 'account_targets', 'service_user')); $tpl->display('services/user/subscribe.tpl'); |
Modified src/www/admin/static/handheld.css from [bb9608a6af] to [9b9dce4df7].
︙ | ︙ | |||
169 170 171 172 173 174 175 | } .filterCategory, .searchMember { width: auto; float: none; } | | | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | } .filterCategory, .searchMember { width: auto; float: none; } fieldset.wikiMain, fieldset.wikiRights, fieldset.wikiEncrypt { float: none; width: auto; } dl.describe { margin: 0 .5em; } |
︙ | ︙ |
Modified src/www/admin/static/print.css from [cf1afc3c77] to [4b92aef442].
1 2 3 4 5 6 7 8 9 10 11 12 | @page { size: A4 landscape; margin: 1cm; } html { height: auto; } body { background: #fff; padding: 0; | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | @page { size: A4 landscape; margin: 1cm; } html { height: auto; } body { background: #fff; padding: 0; margin: 0; font-size: 10pt; } header.header { display: none; } |
︙ | ︙ |
Modified src/www/admin/static/scripts/code_editor.css from [7c23f5ec10] to [e8169a1071].
1 2 3 | .codeEditor { width: 100%; height: 600px; | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 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 40 41 42 43 44 45 46 47 48 49 | .codeEditor { width: 100%; height: 600px; border: 1px solid var(--gBorderColor); background: var(--gLightBackgroundColor); position: relative; display: block; } .codeEditor .sk_help { background: var(--gLightBorderColor); border-top: 2px solid var(--gBorderColor); position: absolute; left: 0; right: 0; bottom: 0; height: 15px; padding: 5px 1em 0; font-family: "Deja Vu Sans Mono", "Droid Sans Mono", "Courier New", Courier, monospace; font-size: 12px; } .codeEditor .sk_toolbar { background: var(--gLightBorderColor); border-bottom: 2px solid var(--gBorderColor); height: 32px; } .codeEditor .sk_toolbar select { float: right; border: none; border-radius: .2em; height: 24px; padding: 1px; padding-left: 24px; margin: 4px .5em; background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEUAAACZm4leYFyOkX1RU09MTkp9f2+ys6KwsZrn5+KanIz///+6u6vGxryDhXtVV1Otpz1oAAAAA3RSTlMA+7omiqY6AAAAgklEQVQI12NI+f9fgQEEfO7e+QBm/BGU+P8fJPrd2LgLCD4AGSCBLCDD8Pfu3bu9QCK/Z86e/esDw4/Hv+/euf0ZyEj7PXPnbCDDI+33kZDQkE8M/11D1969e9eEwRNIlpe332f421Ne0dHRcYnh75k7Z8/cudPEoOIS4uriAlQMAwDpN0taA/g97gAAAABJRU5ErkJggg==") no-repeat 5px center; cursor: pointer; } .codeEditor .sk_toolbar select:hover { background-color: var(--gHoverLinkColor); } .codeEditor .sk_toolbar p { display: inline; padding: .3em .5em; border-radius: .5em; font-size: .9em; |
︙ | ︙ | |||
59 60 61 62 63 64 65 | border-radius: .2em; cursor: pointer; text-indent: -70em; overflow: hidden; background: transparent no-repeat center center; } | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | border-radius: .2em; cursor: pointer; text-indent: -70em; overflow: hidden; background: transparent no-repeat center center; } .codeEditor .sk_toolbar input:hover { background-color: var(--gLightBackgroundColor); } .codeEditor .sk_toolbar .save { margin-left: 2em; background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEU6XIthfJfOXAD8rz6PpsDe3t7+/v6YrsZhe5NVV1Py8vL09PTMzc6+0upyn88gSod8oq0HAAAAAXRSTlOZyTXzhgAAAGxJREFUCNdj4P+kBAT6Hxj+XjYGAtv7DH+fbQOCfSBGKBDkgRi7gQAschQoAmbsXrVq1ToQIw0IQGregQGQ8bCjo6OvDsQ4czS04jmQ8eLMzJiDUMYZkMj3ilAIg/9h6PEjJ4AMhp8zgeD/BwBY4VdD5HZlvAAAAABJRU5ErkJggg=="); } .codeEditor .sk_toolbar .reset { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAAAAAAAD5Q7t/AAABCklEQVR42p2TsUrDUBSGv4RM2qlLXXwBHdoncG3u5tpZx059gojgZAtC3bqqa7cQKH2FWiFZHUSIg5lChi7Xpak312Ma/eHA5Zzz/5fzHw5UMQZ0wxgDOCb5fnQ8Glxe0AR31zdcPW0mpoDOkoDPJKRI41rywdEpRRrTHeZ4drFIY15nh5w/f4jkea/D2aPafeJKTVuyI4Ut7G0NkVDmnbpxXMAHyJJgl1xPW+XT32emC0SA3z75FugO85Ic8Qf0jR33a/p0lgR6PW1pQJtbiPbNK8GzDLPhNBVAKVUphGGIJD7vdWQBi1SBuSGA/P1FFvgNb8vbH7nFaoO5Ja2Uki6Ommt8ME36t4lfRLtlZDAJ4ScAAAAASUVORK5CYII="); } .codeEditor .sk_toolbar .search { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAABGdBTUEAAK/INwWK6QAAADBQTFRF////epWwPGiTdYKPdHqB1tbWWW6Hp6enR2yQc6b/dqncME9tmcz/i5CX5e32w9PmM3gGSwAAAAd0Uk5TAAAAQoTswgXk1s4AAABySURBVAjXYxA0v+4syAAEIqXvQh1BDPN3J88Vgxj3/r07EwtmnDw58y2YcebMHLBI6p/358NADN/3Z75eFhQUZFC5/i4WqIaRwcjtdsrWa0AGEDByr2oAM5i4V82AMBh2nGmCMIBCEAbDrhVghpKS9jYA43soYFw0gPcAAAAASUVORK5CYII="); } .codeEditor .sk_toolbar .search_replace { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEUAAABnVEEAAACEhoVsaWX4liHmz2/8/Pzf398uNDawrKfn5+fOXADj4+P+/v6IioXFYmG9AAAAAnRSTlMAWv0tddIAAACKSURBVAjXY2Dg/w8EAgwMDP/evSuvWwhi7N69Y8UrATDjxurbC4CMn/P3rv9vwMDw3+/J31s9BxkYOl/vm3vjaCiEsSc0hoGhxe+J7dHUgwxckz0nAwUCGDotO3qPph4zYJg8q+P20Zg+AwbJ9rt3VE60f2BgML+76VgHiPH93bt3z8uBjP9g8AEArPJMCYP5JmIAAAAASUVORK5CYII="); } .codeEditor .sk_toolbar .gotoline { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAMFBMVEX///9BQUEVFRWysrREREQ4ODhVVVX7+/vu7u7q6uqcnJy+vr/m5ub19fXc3Nz///89lwBDAAAAB3RSTlMAAILOakNmMhUGwgAAAHtJREFUCNdjYIABQbE0EEhkEMx793r37tdmDILZu1fv3rVqEYNgfv3/u/X/vwEZu4/Xl5eXARnbd96trS1hcPNaWdd7924Jg+///7UdHR1XGIK01lSfnDmzhUFQY8W6N2fOABl+q/a8OXfmCYOg3jugwJlJDIJKEMCAAQCfIDck8YzyWAAAAABJRU5ErkJggg=="); } .codeEditor .sk_toolbar .fullscreen { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEUAAABMTFFOTlBOTlCQ1uMHAAAAA3RSTlMAOcKBmOr4AAAAQUlEQVQI12P4/4D7P8N/B0Yo8XsC23+GZw+4pzM4TmBzYsAGgBKODNcecM9m+D+B7T3DPwfG/Qz/G5iABlzg+g8ANzMax/3kkQoAAAAASUVORK5CYII="); } |
︙ | ︙ | |||
82 83 84 85 86 87 88 | .codeEditor .lineCount { position: absolute; top: 34px; left: 0; bottom: 22px; width: 46px; text-align: right; | | | | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | .codeEditor .lineCount { position: absolute; top: 34px; left: 0; bottom: 22px; width: 46px; text-align: right; border-right: 2px solid var(--gLightBorderColor); overflow: hidden; } .codeEditor .lineCount i { display: block; padding-right: 2px; font-weight: normal; } .codeEditor .lineCount b { display: block; padding-right: 2px; font-weight: normal; } .codeEditor .lineCount b.current { background: var(--gLightBorderColor); } .codeEditor .container { position: absolute; right: 4px; top: 34px; bottom: 22px; |
︙ | ︙ |
Modified src/www/admin/static/scripts/color_helper.js from [65ca233b3d] to [e68352a65f].
1 2 3 4 5 6 7 8 | (function () { if (!document.documentElement.style.setProperty || !window.CSS || !window.CSS.supports || !window.CSS.supports('--var', 0)) { return; } | | > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | (function () { if (!document.documentElement.style.setProperty || !window.CSS || !window.CSS.supports || !window.CSS.supports('--var', 0)) { return; } const logo_limit_x = 170; const bg_color = getVariable('gBgColor').split(',').map(e => parseInt(e, 10)) || [255, 255, 255]; const text_color = getVariable('gTextColor').split(',').map(e => parseInt(e, 10)) || [0, 0, 0]; function getVariable(var_name) { return getComputedStyle(document.documentElement).getPropertyValue('--' + var_name); } function colorToRGB(color, type) { // Conversion vers décimal RGB return color.replace(/^#/, '').match(/.{1,2}/g).map(function (el) { // On limite la luminosité comme ça, c'est pas parfait mais ça marche return Math.min(parseInt(el, 16), type == 'gMainColor' ? 180 : 220); |
︙ | ︙ | |||
24 25 26 27 28 29 30 | }).join(''); } function changeColor(element, color) { let new_color = colorToRGB(color, element); | | > | | > > > > > > > | 30 31 32 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 | }).join(''); } function changeColor(element, color) { let new_color = colorToRGB(color, element); let contrast_color = element == 'gMainColor' ? bg_color : text_color; let sum = contrast_color.reduce((pv, cv) => pv + cv, 0); let change = sum < (127*3) ? 5 : -5; while (!checkContrast(new_color, contrast_color)) { new_color[0] += change; new_color[1] += change; new_color[2] += change; } for (i in new_color) { new_color[i] = Math.max(new_color[i], 0); new_color[i] = Math.min(new_color[i], 255); } console.log(new_color, contrast_color, change); // Mise à jour variable CSS document.documentElement.style.setProperty('--' + element, new_color.join(',')); applyColors(); return new_color.join(','); } |
︙ | ︙ | |||
158 159 160 161 162 163 164 | for(var y = 0; y < imgData.height; y++) { for(var x = 0; x < imgData.width; x++) { var avg = (data[i] * 0.3 + data[i+1] * 0.59 + data[i+2] * 0.11); var b = avg < 127 && (data[i+3] > 127); data[i] = b ? avg : 255; // red data[i+1] = b ? avg : 255; // green data[i+2] = b ? avg : 255; // blue | | | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | for(var y = 0; y < imgData.height; y++) { for(var x = 0; x < imgData.width; x++) { var avg = (data[i] * 0.3 + data[i+1] * 0.59 + data[i+2] * 0.11); var b = avg < 127 && (data[i+3] > 127); data[i] = b ? avg : 255; // red data[i+1] = b ? avg : 255; // green data[i+2] = b ? avg : 255; // blue data[i+3] = b ? (x >> logo_limit_x ? 50 : 150) : 0; i += 4; } } ctx.putImageData(imgData, 0, 0); var i = canvas.toDataURL('image/png'); |
︙ | ︙ |
Modified src/www/admin/static/scripts/datepicker2.js from [6f612d2aa2] to [317a9279e3].
︙ | ︙ | |||
14 15 16 17 18 19 20 | this.button = button; this.input = input; this.date = null; Object.assign(this, { format: 0, // 0 = Y-m-d, 1 = d/m/Y lang: 'fr', | | < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | this.button = button; this.input = input; this.date = null; Object.assign(this, { format: 0, // 0 = Y-m-d, 1 = d/m/Y lang: 'fr', class: 'datepicker' }, config); var c = document.createElement('dialog'); c.className = this.class; this.container = button.parentNode.insertBefore(c, button.nextSibling); button.onclick = () => { this.container.hasAttribute('open') ? this.close() : this.open() }; |
︙ | ︙ | |||
183 184 185 186 187 188 189 | if (this.input) { this.input.value = v; } this.close(); | > | | < > | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | if (this.input) { this.input.value = v; } this.close(); event = document.createEvent('HTMLEvents'); event.initEvent('change', true, true); event.eventName = 'change'; this.input.dispatchEvent(event); } focus() { this.container.querySelectorAll('tbody td').forEach((cell) => { var v = parseInt(cell.innerHTML, 10); |
︙ | ︙ |
Modified src/www/admin/static/scripts/file_input.js from [c1bd753cc3] to [4e17f68bb7].
︙ | ︙ | |||
33 34 35 36 37 38 39 | if (total >= max_size - 1000) { alert("Les fichiers sélectionnés dépassent la taille maximale autorisée. Merci de choisir moins de fichiers."); e.preventDefault(); e.stopPropagation(); return false; } | | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | if (total >= max_size - 1000) { alert("Les fichiers sélectionnés dépassent la taille maximale autorisée. Merci de choisir moins de fichiers."); e.preventDefault(); e.stopPropagation(); return false; } input.form.firstElementChild.classList.add('progressing'); }; const updateLabel = () => { let l; if (dt.files.length == 0) { l = label_unselected; |
︙ | ︙ |
Added src/www/admin/static/scripts/lib/unzipit.min.js version [8729f4e48a].
> > | 1 2 | /* unzipit@1.3.6, license MIT */ !function(){function e(e){return e.arrayBuffer?e.arrayBuffer():new Promise(((t,r)=>{const n=new FileReader;n.addEventListener("loadend",(()=>{t(n.result)})),n.addEventListener("error",r),n.readAsArrayBuffer(e)}))}function t(e){return"undefined"!=typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer}"undefined"!=typeof process&&process.versions&&void 0!==process.versions.node&&process.versions.electron;class r{constructor(e){this.blob=e}async getLength(){return this.blob.size}async read(t,r){const n=this.blob.slice(t,t+r),i=await e(n);return new Uint8Array(i)}async sliceAsBlob(e,t,r=""){return this.blob.slice(e,e+t,r)}}function n(e,t){for(var r,n,i,o,a=e.length,f=s.bl_count,c=0;c<=t;c++)f[c]=0;for(c=1;c<a;c+=2)f[e[c]]++;var d=s.next_code;for(r=0,f[0]=0,n=1;n<=t;n++)r=r+f[n-1]<<1,d[n]=r;for(i=0;i<a;i+=2)0!=(o=e[i+1])&&(e[i]=d[o],d[o]++)}function i(e,t,r){for(var n=e.length,i=s.rev15,o=0;o<n;o+=2)if(0!=e[o+1])for(var a=o>>1,f=e[o+1],c=a<<4|f,d=t-f,l=e[o]<<d,u=l+(1<<d);l!=u;){r[i[l]>>>15-t]=c,l++}}function o(e,t){for(var r=s.rev15,n=15-t,i=0;i<e.length;i+=2){var o=e[i]<<t-e[i+1];e[i]=r[o]>>>n}}const s=(a=Uint16Array,f=Uint32Array,{next_code:new a(16),bl_count:new a(16),ordr:[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],of0:[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,999,999,999],exb:[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0],ldef:new a(32),df0:[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,65535,65535],dxb:[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0],ddef:new f(32),flmap:new a(512),fltree:[],fdmap:new a(32),fdtree:[],lmap:new a(32768),ltree:[],ttree:[],dmap:new a(32768),dtree:[],imap:new a(512),itree:[],rev15:new a(32768),lhst:new f(286),dhst:new f(30),ihst:new f(19),lits:new f(15e3),strt:new a(65536),prev:new a(32768)});var a,f;!function(){for(var e=0;e<32768;e++){var t=e;t=(4278255360&(t=(4042322160&(t=(3435973836&(t=(2863311530&t)>>>1|(1431655765&t)<<1))>>>2|(858993459&t)<<2))>>>4|(252645135&t)<<4))>>>8|(16711935&t)<<8,s.rev15[e]=(t>>>16|t<<16)>>>17}function r(e,t,r){for(;0!=t--;)e.push(0,r)}for(e=0;e<32;e++)s.ldef[e]=s.of0[e]<<3|s.exb[e],s.ddef[e]=s.df0[e]<<4|s.dxb[e];r(s.fltree,144,8),r(s.fltree,112,9),r(s.fltree,24,7),r(s.fltree,8,8),n(s.fltree,9),i(s.fltree,9,s.flmap),o(s.fltree,9),r(s.fdtree,32,5),n(s.fdtree,5),i(s.fdtree,5,s.fdmap),o(s.fdtree,5),r(s.itree,19,0),r(s.ltree,286,0),r(s.dtree,30,0),r(s.ttree,320,0)}();const c={table:function(){for(var e=new Uint32Array(256),t=0;t<256;t++){for(var r=t,n=0;n<8;n++)1&r?r=3988292384^r>>>1:r>>>=1;e[t]=r}return e}(),update:function(e,t,r,n){for(var i=0;i<n;i++)e=c.table[255&(e^t[r+i])]^e>>>8;return e},crc:function(e,t,r){return 4294967295^c.update(4294967295,e,t,r)}};class d{constructor(e,t){this._reader=e,this._rawEntry=t,this.name=t.name,this.nameBytes=t.nameBytes,this.size=t.uncompressedSize,this.compressedSize=t.compressedSize,this.comment=t.comment,this.commentBytes=t.commentBytes,this.compressionMethod=t.compressionMethod,this.lastModDate=null,this.isDirectory=0===t.uncompressedSize&&t.name.endsWith("/"),this.encrypted=!!(1&t.generalPurposeBitFlag)}async blob(e="application/octet-stream"){return await async function(e,r,n){const{decompress:i,fileDataStart:o}=await async function(e,t){if(1&t.generalPurposeBitFlag)throw new Error("encrypted entries not supported");const r=await l(e,t.relativeOffsetOfLocalHeader,30),n=await e.getLength(),i=p(r,0);if(67324752!==i)throw new Error(`invalid local file header signature: 0x${i.toString(16)}`);const o=m(r,26),s=m(r,28),a=t.relativeOffsetOfLocalHeader+r.length+o+s;let f;if(0===t.compressionMethod)f=!1;else{if(8!==t.compressionMethod)throw new Error(`unsupported compression method: ${t.compressionMethod}`);f=!0}const c=a,d=c+t.compressedSize;if(0!==t.compressedSize&&d>n)throw new Error(`file data overflows file bounds: ${c} + ${t.compressedSize} > ${n}`);return{decompress:f,fileDataStart:c}}(e,r),s=await async function(e,t,r,n){if(e.sliceAsBlob)return await e.sliceAsBlob(t,r,n);return await e.read(t,r)}(e,o,r.compressedSize,n);if(a=s,"undefined"!=typeof Blob&&a instanceof Blob)return s;var a;return new Blob([t(s.buffer)?new Uint8Array(s):s],{type:n})}(this._reader,this._rawEntry,e)}async arrayBuffer(){return await readEntryDataAsArrayBuffer(this._reader,this._rawEntry)}async text(){const e=await this.arrayBuffer();return y(new Uint8Array(e))}}async function l(e,t,r){return await e.read(t,r)}const u={unsigned:()=>0};function m(e,t){return e[t]+256*e[t+1]}function p(e,t){return e[t]+256*e[t+1]+65536*e[t+2]+16777216*e[t+3]}function w(e,t){return p(e,t)+4294967296*p(e,t+4)}const h=new TextDecoder;function y(e,r){return t(e.buffer)&&(e=new Uint8Array(e)),h.decode(e)}async function g(e,t,r,n){const i=t-20,o=await l(e,i,20);if(117853008!==p(o,0))throw new Error("invalid zip64 end of central directory locator signature");const s=w(o,8),a=await l(e,s,56);if(101075792!==p(a,0))throw new Error("invalid zip64 end of central directory record signature");const f=w(a,32),c=w(a,40);return b(e,w(a,48),c,f,r,n)}async function b(e,t,r,n,i,o){let s=0;const a=await l(e,t,r),f=[];for(let e=0;e<n;++e){const e=a.subarray(s,s+46),t=p(e,0);if(33639248!==t)throw new Error(`invalid central directory file header signature: 0x${t.toString(16)}`);const r={versionMadeBy:m(e,4),versionNeededToExtract:m(e,6),generalPurposeBitFlag:m(e,8),compressionMethod:m(e,10),lastModFileTime:m(e,12),lastModFileDate:m(e,14),crc32:p(e,16),compressedSize:p(e,20),uncompressedSize:p(e,24),fileNameLength:m(e,28),extraFieldLength:m(e,30),fileCommentLength:m(e,32),internalFileAttributes:m(e,36),externalFileAttributes:p(e,38),relativeOffsetOfLocalHeader:p(e,42)};if(64&r.generalPurposeBitFlag)throw new Error("strong encryption is not supported");s+=46;const n=a.subarray(s,s+r.fileNameLength+r.extraFieldLength+r.fileCommentLength);r.nameBytes=n.slice(0,r.fileNameLength),r.name=y(r.nameBytes);const i=r.fileNameLength+r.extraFieldLength,o=n.slice(r.fileNameLength,i);r.extraFields=[];let c=0;for(;c<o.length-3;){const e=m(o,c+0),t=c+4,n=t+m(o,c+2);if(n>o.length)throw new Error("extra field length exceeds extra field buffer size");r.extraFields.push({id:e,data:o.slice(t,n)}),c=n}if(r.commentBytes=n.slice(i,i+r.fileCommentLength),r.comment=y(r.commentBytes),s+=n.length,4294967295===r.uncompressedSize||4294967295===r.compressedSize||4294967295===r.relativeOffsetOfLocalHeader){const e=r.extraFields.find((e=>1===e.id));if(!e)return new Error("expected zip64 extended information extra field");const t=e.data;let n=0;if(4294967295===r.uncompressedSize){if(n+8>t.length)throw new Error("zip64 extended information extra field does not include uncompressed size");r.uncompressedSize=w(t,n),n+=8}if(4294967295===r.compressedSize){if(n+8>t.length)throw new Error("zip64 extended information extra field does not include compressed size");r.compressedSize=w(t,n),n+=8}if(4294967295===r.relativeOffsetOfLocalHeader){if(n+8>t.length)throw new Error("zip64 extended information extra field does not include relative header offset");r.relativeOffsetOfLocalHeader=w(t,n),n+=8}}const d=r.extraFields.find((e=>28789===e.id&&e.data.length>=6&&1===e.data[0]&&p(e.data,1)),u.unsigned(r.nameBytes));if(d&&(r.fileName=y(d.data.slice(5))),0===r.compressionMethod){let e=r.uncompressedSize;if(0!=(1&r.generalPurposeBitFlag)&&(e+=12),r.compressedSize!==e)throw new Error(`compressed size mismatch for stored file: ${r.compressedSize} != ${e}`)}f.push(r)}return{zip:{comment:i,commentBytes:o},entries:f.map((t=>new d(e,t)))}}async function v(e){let t;if(!("undefined"!=typeof Blob&&e instanceof Blob))throw new Error("unsupported source type");t=new r(e);const n=await t.getLength();if(n>Number.MAX_SAFE_INTEGER)throw new Error(`file too large. size: ${n}. Only file sizes up 4503599627370496 bytes are supported`);return await async function(e,t){const r=Math.min(65557,t),n=t-r,i=await l(e,n,r);for(let t=r-22;t>=0;--t){if(101010256!==p(i,t))continue;const r=new Uint8Array(i.buffer,i.byteOffset+t,i.byteLength-t),o=m(r,4);if(0!==o)throw new Error(`multi-volume zip files are not supported. This is volume: ${o}`);const s=m(r,10),a=p(r,12),f=p(r,16),c=m(r,20),d=r.length-22;if(c!==d)throw new Error(`invalid comment length. expected: ${d}, actual: ${c}`);const l=new Uint8Array(r.buffer,r.byteOffset+22,c),u=y(l);return 65535===s||4294967295===f?await g(e,n+t,u,l):await b(e,f,a,s,u,l)}throw new Error("could not find end of central directory. maybe not zip file")}(t,n)}window.unzipit=async function(e){const{zip:t,entries:r}=await v(e);return{zip:t,entries:Object.fromEntries(r.map((e=>[e.name,e])))}}}(); |
Added src/www/admin/static/scripts/unzip_restore.js version [82f3020360].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 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 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 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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | (function () { let form = document.getElementById('restoreDocuments'); form.style.display = 'block'; const MAX_UNCOMPRESSED_SIZE = 1024*1024*1024*10; // 10 GB const MAX_FILE_SIZE = form.querySelector('input[name="MAX_FILE_SIZE"]').value - 250; let status = document.querySelector('#' + form.id + ' .progress-status'); let input = document.getElementById('f_file'); let failed_entries = []; let fd = new FormData(form); fd.delete('file'); fd.append('restore', 1); form.addEventListener('submit', processZip); async function processZip(e) { form.firstElementChild.classList.add('progressing'); form.firstElementChild.disabled = true; e.preventDefault(); if (!input.files.length) { alert('Aucun fichier sélectionné'); return false; } if (!input.files[0].name.match(/\.zip$/i)) { alert('Le fichier sélectionné n\'est pas un fichier ZIP.'); return false; } try { var {entries} = await unzipit(input.files[0]); } catch (error) { console.log(error); alert(error); location.href = location.href; return; } let total_size = 0; // print all entries and their sizes for (const [name, entry] of Object.entries(entries)) { total_size += entry.size; } if (total_size > MAX_UNCOMPRESSED_SIZE) { alert('Archive ZIP trop grosse !'); return; } for (const [name, entry] of Object.entries(entries)) { // Skip directories if (entry.isDirectory) { continue; } if (entry.size > MAX_FILE_SIZE) { // Skip files that are too large failed_entries.push(name); continue; } if (entry.size == 0) { // Skip empty files continue; } try { const blob = await entry.blob(); const r = await upload(name, blob, entry.compressionMethod == 8 ? true : false); } catch (error) { console.log(error); alert(error); location.href = location.href; return; } } location.href = form.action + '?ok&failed=' + failed_entries.length; return false; } async function upload(name, blob, compressed) { let dt = new DataTransfer(); let file_name = name.replace(/^.*\/([^\/]+)$/, '$1'); let f = new File([blob], file_name); status.innerHTML = name; dt.items.add(f); fd.delete('file1'); fd.delete('target'); fd.delete('compressed'); fd.append('target', name); fd.append('compressed', compressed ? 1 : 0); fd.append('file1', dt.files[0], file_name); const response = await fetch(form.action, { method: 'POST', body: fd }); if (!response.ok) { const message = `Erreur du serveur : ${response.status}`; throw new Error(message); } const body = await response.text(); if (body.substr(0, 1) != '{') { console.log(body); throw "Réponse invalide du serveur"; } let result = JSON.parse(body); if (result.error) { console.log(body); throw result.error; } return true; } }()); |
Modified src/www/admin/static/scripts/wiki_editor.css from [531ffd0eea] to [57a2c80c94].
1 2 | .textEditor { border-radius: .5em; | | | | | | | | 1 2 3 4 5 6 7 8 9 10 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 40 41 42 43 44 45 46 47 | .textEditor { border-radius: .5em; background: var(--gLightBorderColor); padding: 1%; overflow: hidden; position: relative; } .textEditor textarea { border: none; margin: 0; background: var(--gLightBackgroundColor); border-radius: .5em; height: 96%; width: 98%; } nav.te { margin-bottom: .5em; height: 30px; } nav.te button { text-decoration: none; cursor: pointer; background: var(--gLightBackgroundColor) no-repeat center center; display: inline-block; vertical-align: bottom; transition: all .2s; border: 1px solid var(--gBorderColor); box-shadow: 2px 2px 5px var(--gBorderColor); } nav.te .bold, nav.te .italic, nav.te .title, nav.te .link { font-family: Georgia, "Times New Roman", serif; } nav.te .bold { font-weight: bold; } nav.te .italic { font-style: italic; } nav.te .link { text-decoration: underline; color: var(--gLinkColor); } nav.te .fullscreen { text-indent: -70em; width: 32px; overflow: hidden; } |
︙ | ︙ | |||
115 116 117 118 119 120 121 | .textEditor.iframe nav button.close, .textEditor.iframe nav button.reload { display: inline-block; } .textEditor iframe { border: none; | | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | .textEditor.iframe nav button.close, .textEditor.iframe nav button.reload { display: inline-block; } .textEditor iframe { border: none; background: rgb(var(--gBgColor)); border-radius: .5em; padding: 1%; width: 98%; } .textEditor iframe.hidden { visibility: hidden; |
︙ | ︙ | |||
161 162 163 164 165 166 167 | background: rgba(0, 0, 0, 0.75); } form#insertImage fieldset { box-shadow: 5px 5px 10px #000; margin: 1em; padding: 1em; | | < < | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | background: rgba(0, 0, 0, 0.75); } form#insertImage fieldset { box-shadow: 5px 5px 10px #000; margin: 1em; padding: 1em; background: var(--gLightBackgroundColor); border-radius: .5em; text-align: center; } form#insertImage dt { margin: .2em 0; } form#insertImage .align input { font-size: 1.2em; line-height: 32px; background-position: 5px center; background-repeat: no-repeat; padding: 5px; padding-left: 42px; border-radius: 5px; margin: .5em; } form#insertImage .align input[name=""] { background-image: url("../pics/img_flow.png"); } |
︙ | ︙ | |||
201 202 203 204 205 206 207 | form#insertImage .align input[name="center"] { background-image: url("../pics/img_center.png"); } form#insertImage .cancel input { font-size: 0.8em; | < < < < < < < | < < < < | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | form#insertImage .align input[name="center"] { background-image: url("../pics/img_center.png"); } form#insertImage .cancel input { font-size: 0.8em; margin: .5em; opacity: 0.8; } #confirm_saved { position: absolute; top: .5em; right: 10em; text-align: center; transition: all .5s, opacity 2s; } |
Modified src/www/admin/static/scripts/wiki_fichiers.js from [6d13b317ce] to [88a6ff9b9e].
︙ | ︙ | |||
21 22 23 24 25 26 27 | f.querySelector('dd.image').innerHTML = ''; var img = document.createElement('img'); img.src = file.thumb; img.alt = ''; f.querySelector('dd.image').appendChild(img); | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | f.querySelector('dd.image').innerHTML = ''; var img = document.createElement('img'); img.src = file.thumb; img.alt = ''; f.querySelector('dd.image').appendChild(img); f.querySelector('dd.cancel [type=reset]').onclick = function() { f.style.display = 'none'; if (from_upload) { location.href = location.href; } }; |
︙ | ︙ |
Modified src/www/admin/static/styles/01-layout.css from [9046a79977] to [9c3400eb48].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* marron : #9c4f15 rgb(156, 79, 21) orange : #d98628 rgb(217, 134, 40) */ :root { --gBgColor: 255, 255, 255; --gMainColor: 156, 79, 21; --gSecondColor: 217, 134, 40; --gBgImage: url("../gdin_bg.png"); } html { width: 100%; height: 100%; } body { font-size: 100%; | > > > > > > > > > > > > > > > > > > > | > > | > > > > | 1 2 3 4 5 6 7 8 9 10 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 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 | /* marron : #9c4f15 rgb(156, 79, 21) orange : #d98628 rgb(217, 134, 40) */ /* Light colors */ :root { --gBgColor: 255, 255, 255; --gTextColor: 0, 0, 0; --gBorderColor: #666; --gLightBorderColor: #ccc; --gLightBackgroundColor: #eee; --gLinkColor: blue; --gHoverLinkColor: 127, 0, 0; --gMainColor: 156, 79, 21; --gSecondColor: 217, 134, 40; --gBgImage: url("../gdin_bg.png"); } /* Dark colors */ html.dark { --gBgColor: 30, 30, 30; --gTextColor: 225, 225, 225; --gBorderColor: #999; --gLightBorderColor: #333; --gLightBackgroundColor: #222; --gLinkColor: #99f; --gHoverLinkColor: 250, 127, 127; } html { width: 100%; height: 100%; } body { font-size: 100%; color: rgb(var(--gTextColor)); font-family: "Trebuchet MS", Arial, Helvetica, Sans-serif; padding-bottom: 1em; background: rgb(var(--gBgColor)) var(--gBgImage) no-repeat 0px 0px fixed; } main { margin: 0px 1em 1em 180px; position: relative; } main img { max-width: 100%; } a { color: var(--gLinkColor); } a:hover { color: rgb(var(--gHoverLinkColor)); } .header h1 { color: rgb(var(--gMainColor)); margin-left: 180px; margin-bottom: 0.4em; } |
︙ | ︙ | |||
66 67 68 69 70 71 72 | top: 0; bottom: 0; background: rgb(var(--gMainColor)) var(--gBgImage) no-repeat 0px 0px; } .header .menu::-webkit-scrollbar { width: 8px; | | | | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | top: 0; bottom: 0; background: rgb(var(--gMainColor)) var(--gBgImage) no-repeat 0px 0px; } .header .menu::-webkit-scrollbar { width: 8px; background: rgba(var(--gBgColor), 0.25); box-shadow: inset 0px 0px 10px #666; } .header .menu::-webkit-scrollbar-thumb { background: rgba(var(--gBgColor), 0.5); border-radius: 10px; } .header .menu i { font-style: normal; } |
︙ | ︙ | |||
110 111 112 113 114 115 116 | } .header .menu a b { float: right; text-decoration: none; margin-top: -.2em; font-size: 20pt; | | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | } .header .menu a b { float: right; text-decoration: none; margin-top: -.2em; font-size: 20pt; color: rgba(var(--gBgColor), .5); } .header .menu li.current > a b { color: rgba(var(--gSecondColor), 0.5); } |
︙ | ︙ |
Modified src/www/admin/static/styles/02-common.css from [72a91c6a02] to [e0f654a9f7].
︙ | ︙ | |||
23 24 25 26 27 28 29 | .block table { margin: 1rem 0; } .block table th, .block table td { vertical-align: top; padding: .2rem .4rem; | | | > > | | | | | | 23 24 25 26 27 28 29 30 31 32 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 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 101 102 | .block table { margin: 1rem 0; } .block table th, .block table td { vertical-align: top; padding: .2rem .4rem; border: 1px solid var(--gBorderColor); } .alert.block, .error.block, .confirm.block, .help.block { border: 1px solid var(--gLightBorderColor); padding: .5em; margin: .5em 0; border-radius: .3em; padding-left: 3em; position: relative; clear: both; color: #000; } .alert.block { border-color: #cc0; background-color: #ffc; } .error.block { border-color: #c00; background-color: #fcc; } .confirm.block { border-color: #0c0; background-color: #cfc; } .help.block { color: rgb(var(--gTextColor)); border-color: var(--gLightBorderColor); background-color: var(--gLightBackgroundColor); } .confirm.block::before, .alert.block::before, .error.block::before, .help.block::before { font-family: "gicon"; left: .5em; top: .2em; position: absolute; font-size: 1.5em; text-shadow: 2px 2px 5px var(--gLightBorderColor); } .confirm.block::before { content: "☑"; color: green; } .alert.block::before { content: "⚠"; color: yellow; } .error.block::before { content: "⚠"; color: red; } .help.block::before { content: "❓"; color: var(--gBorderColor); } .help { color: var(--gBorderColor); } p.help:not(.block) { margin: 1em; } .help ul li { |
︙ | ︙ | |||
115 116 117 118 119 120 121 | margin-left: 1.5em; list-style: disc; } .ruler { margin: .5em; text-align: center; | < | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | margin-left: 1.5em; list-style: disc; } .ruler { margin: .5em; text-align: center; overflow: hidden; } .ruler:before, .ruler:after { background-color: var(--gLightBorderColor); content: ""; display: inline-block; height: 1px; position: relative; vertical-align: middle; width: 50%; } |
︙ | ︙ | |||
146 147 148 149 150 151 152 | .num a, a.num { text-decoration: none; border-radius: .5rem; display: inline-block; text-align: center; padding: 0 .3rem; background: rgba(var(--gMainColor), 0.7); | | | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | .num a, a.num { text-decoration: none; border-radius: .5rem; display: inline-block; text-align: center; padding: 0 .3rem; background: rgba(var(--gMainColor), 0.7); color: rgb(var(--gBgColor)); white-space: pre; } .permissions b { border: 2px solid #999; border-radius: 1em; color: #000; |
︙ | ︙ | |||
281 282 283 284 285 286 287 | dl.list dt { font-size: 1.2em; font-weight: bold; margin-top: .8em; } dl.list dd.desc { | | | < < | 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 323 324 | dl.list dt { font-size: 1.2em; font-weight: bold; margin-top: .8em; } dl.list dd.desc { color: var(--gLightBorderColor); } dl.describe { margin-bottom: 1rem; display: grid; grid-template: auto / 15rem 1fr; } dl.describe > dt { grid-column: 1; margin: .2rem .5rem; text-align: right; color: var(--gBorderColor); align-self: start; } dl.describe > dd { grid-column: 2; margin: .2rem .5rem; align-self: center; } dl.describe ul { margin-left: 1.5em; list-style-type: disc; } dl.cotisation { background: rgba(var(--gSecondColor), 0.2); padding: .5em; border-radius: .5em; margin: 1em; } dl.cotisation dt { |
︙ | ︙ | |||
335 336 337 338 339 340 341 | float: right; margin: .5em; background: rgba(var(--gSecondColor), 0.2); border-radius: .5em; border: 2px solid rgba(var(--gSecondColor), 0.5); padding: .5em; z-index: 200; | | | | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | float: right; margin: .5em; background: rgba(var(--gSecondColor), 0.2); border-radius: .5em; border: 2px solid rgba(var(--gSecondColor), 0.5); padding: .5em; z-index: 200; color: var(--gBorderColor); } aside.describe dl.describe { display: block; } aside.describe dl.describe dt { text-align: left; font-weight: bold; color: rgb(var(--gTextColor)); } .hidden { display: none; } img.qrcode { |
︙ | ︙ | |||
388 389 390 391 392 393 394 | content: "↓"; position: absolute; left: 0; top: 0; bottom: 0; /* From .icn-btn */ cursor: pointer; | < | | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | content: "↓"; position: absolute; left: 0; top: 0; bottom: 0; /* From .icn-btn */ cursor: pointer; border: 1px solid rgba(var(--gMainColor), 0.5); background-color: rgba(var(--gSecondColor), 0.1); user-select: none; display: inline-block; font-size: inherit; border-radius: .2em; padding: .2em .4em; margin: auto .5em; height: 1em; white-space: pre; transition: color .3s, background-color .3s; font-family: "gicon", sans-serif; text-shadow: 1px 1px 1px var(--gLightBorderColor); font-size: 1.2em; } details[open] summary::after { content: "↑"; } |
︙ | ︙ | |||
438 439 440 441 442 443 444 | text-align: center; padding: .5rem; margin: .5rem; } .files-list aside small { display: block; | | | | | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 | text-align: center; padding: .5rem; margin: .5rem; } .files-list aside small { display: block; color: var(--gBorderColor); } nav.breadcrumbs { margin: .5em 0; color: var(--gLightBorderColor); } nav.breadcrumbs a { color: var(--gBorderColor); } nav.breadcrumbs ul, nav.breadcrumbs li { list-style-type: none; display: inline; } |
︙ | ︙ | |||
471 472 473 474 475 476 477 | float: right; } aside.quota { background: rgba(var(--gMainColor), 0.1); border-radius: .5rem; padding: .2rem .5rem; | | | 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | float: right; } aside.quota { background: rgba(var(--gMainColor), 0.1); border-radius: .5rem; padding: .2rem .5rem; color: rgb(var(--gTextColor)); margin: .5em 0; } aside.quota i { font-style: normal; } |
︙ | ︙ | |||
517 518 519 520 521 522 523 | } .search-results h3 { margin: .3em 0; } .search-results h3 a { | < | 515 516 517 518 519 520 521 522 523 | } .search-results h3 { margin: .3em 0; } .search-results h3 a { font-weight: normal; } |
Modified src/www/admin/static/styles/03-forms.css from [48a1aece0a] to [d01f0ddad6].
1 2 | /* Forms */ fieldset { | | | > > > > | | < < < < < | | > > > > | | | 1 2 3 4 5 6 7 8 9 10 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 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 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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | /* Forms */ fieldset { border: 1px solid var(--gLightBorderColor); padding: 0.8em 1em 0 1em; margin-bottom: 1em; padding: 0.5em; } fieldset legend { padding: 0 0.5em; font-weight: bold; color: rgb(var(--gTextColor)); } /* Override selector in 06-tables.css */ table tr.clickable:hover, table tr.clickable:nth-child(even):hover { cursor: pointer; color: #633; background: #ffc; } table tr.clickable:hover button, table tr.focused button { color: rgb(var(--gHoverLinkColor)); } table tr.focused { color: #633; background: #ffc !important; box-shadow: 0 0 5px .2rem #990; } dl dt label { font-weight: bold; } fieldset dl dt b { color: rgb(var(--gHoverLinkColor)); font-size: 0.7em; font-weight: normal; vertical-align: super; } fieldset dl dt i { color: var(--gLightBorderColor); font-size: 0.7em; font-weight: normal; vertical-align: super; } fieldset dl dd { padding: 0.2em 0.5em 0.2em 1em; } fieldset dl dd ol, fieldset dl dd ul { margin-left: 1.5em; } fieldset dl dl { margin: .5em 0 .5em 1.2em; } label:hover { cursor: pointer; } input[type=checkbox] + label:hover { border: none; } /* We can't use :not([type=checkbox]):not([type=radio]) here as it is too specific and then it's a mess to override the selector after... */ input[type=text], input[type=number], input[type=color], input[type=date], input[type=datetime-local], input[type=datetime], input[type=time], input[type=week], input[type=email], input[type=file], input[type=url], input[type=month], input[type=password], input[type=range], input[type=search], input[type=tel], textarea, select, .input-list, .file-selector { padding: .4rem .6rem; font-family: inherit; min-width: 20em; max-width: 100%; border: 1px solid rgb(var(--gMainColor)); font-size: inherit; background: rgb(var(--gBgColor)); color: rgb(var(--gTextColor)); border-radius: .25rem; transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out; } textarea.full-width { width: calc(100% - 1rem); } input:not(:placeholder-shown):focus:invalid { border-color: rgb(var(--gHoverLinkColor)); } input.time { text-align: center; padding: .2em 0; } /* Fake checkbox and radio buttons */ input[type=checkbox], input[type=radio] { position: absolute; opacity: 0; } input[type=checkbox] + label::before, input[type=radio] + label::before { display: inline-block; width: 1em; height: 1em; text-align: center; transition: color .2s, box-shadow .2s ease-in-out; text-shadow: 1px 1px 3px var(--gLightBorderColor); cursor: pointer; font-family: gicon; font-size: 1.2rem; font-weight: normal; color: rgb(var(--gMainColor)); margin-right: .5em; border-radius: .25rem; |
︙ | ︙ | |||
136 137 138 139 140 141 142 | } input:hover + label::before { color: rgb(var(--gSecondColor)); } input:checked + label::before { | | | | | | | | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > | | | > > | | | | | | | 139 140 141 142 143 144 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 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 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 | } input:hover + label::before { color: rgb(var(--gSecondColor)); } input:checked + label::before { text-shadow: 1px 1px 5px rgba(var(--gSecondColor), 0.5); } #queryBuilder input[type=checkbox] { position: unset; opacity: unset; } input:focus, button:focus, select:focus, textarea:focus, input[type=radio]:focus + label::before, input[type=checkbox]:focus + label::before { box-shadow: 0 0 5px .2rem rgba(var(--gMainColor), 0.5); outline: 0; } /* buttons */ input[type=submit], input[type=button], button, input[type=file] { border-radius: 1em; border: none; box-shadow: 0px 0px 5px 0 var(--gLightBorderColor); cursor: pointer; border: 2px solid rgba(var(--gMainColor), 0.5); background: rgba(var(--gSecondColor), 0.2); display: inline-block; font-size: inherit; border-radius: .2em; padding: .2em .4em; margin: .2em .5em; text-decoration: none; transition: color .3s, background-color .3s; color: rgb(var(--gTextColor)); } a.icn-btn { cursor: pointer; color: rgb(var(--gTextColor)); border: 1px solid rgba(var(--gMainColor), 0.5); background: rgba(var(--gSecondColor), 0.1); user-select: none; display: inline-block; font-size: inherit; border-radius: .2em; padding: .2em .4em; margin: .2em .5em; white-space: pre; transition: color .3s, background-color .3s; text-decoration: underline; } [data-icon]:before, .main[data-icon]:after { display: inline-block; font-family: "gicon", sans-serif; text-shadow: 1px 1px 1px var(--gLightBorderColor); padding-right: .5em; font-size: 1.2em; line-height: .8em; vertical-align: middle; content: attr(data-icon); } [data-icon]:empty:before { padding: 0; } .icn, .icnl { font-family: "gicon", sans-serif; font-style: normal; font-weight: normal; speak: none; font-variant: normal; text-transform: none; position: relative; } .actions .icn, .icn.action { text-decoration: none; border-radius: 1em; display: inline-block; text-align: center; font-size: 1.2em; line-height: .8em; vertical-align: middle; padding: .2em; font-family: "gicon", sans-serif; color: rgb(var(--gMainColor)); text-shadow: 1px 1px 1px var(--gBorderColor); border: none; cursor: pointer; position: relative; z-index: 200; } button.main, .icn-btn.main { color: rgb(var(--gTextColor)); font-size: 1.2em; border-radius: 1em; padding: .5em 1em; } button.main[data-icon]:before, .icn-btn.main:before { display: none; } button.main[data-icon]:after, .icn-btn[data-icon]:after { padding: 0; padding-left: .5em; padding-right: 0; color: rgba(var(--gSecondColor)); font-size: 1.5rem; line-height: .2em; } .submit .minor { font-size: .9em; } input[type=submit]:hover, input[type=button]:hover, button:hover, a.icn-btn:hover, input[type=file]:hover, .radio-btn:hover div, a.num:hover, .num a:hover { background-color: rgba(var(--gSecondColor), 0.2); color: rgb(var(--gHoverLinkColor)) !important; border-color: rgb(var(--gSecondColor)); } input[type=submit]:active, input[type=button]:active, button:active, input[type=file]:active { box-shadow: 0 0 10px .1rem rgb(var(--gSecondColor)); } input[type=color] { cursor: pointer; } input.resetButton { margin-left: 1em; } input[readonly], input.disabled, input[disabled], textarea[disabled], select[disabled] { cursor: not-allowed; color: var(--gBorderColor); background-color: var(--gLightBackgroundColor); border-color: var(--gLightBorderColor); } input[disabled]:hover, input[readonly]:hover { background-color: unset; color: unset; border-color: unset; } input[disabled] + label { color: var(--gBorderColor); } input[disabled] + label::before { color: var(--gBorderColor); cursor: not-allowed; } select, input[size], input[type=color], button, input[type=button], input[type=submit], input[type=number] { min-width: 0; } |
︙ | ︙ | |||
283 284 285 286 287 288 289 | display: table-cell; border: 1px solid rgba(var(--gSecondColor), 0.5); background-color: rgba(var(--gSecondColor), 0.1); font-size: inherit; border-radius: .2em; padding: .2em .4em; transition: color .3s, background-color .3s; | | | | | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | display: table-cell; border: 1px solid rgba(var(--gSecondColor), 0.5); background-color: rgba(var(--gSecondColor), 0.1); font-size: inherit; border-radius: .2em; padding: .2em .4em; transition: color .3s, background-color .3s; color: rgb(var(--gTextColor)); } form .radio-btn h3 { text-decoration: underline; } form .radio-btn input { margin: 1em; } form .radio-btn .help { margin: 0; font-size: .9em; } form .radio-btn input:checked + label div { background-color: rgba(var(--gSecondColor), 0.3); } /* Custom list input */ |
︙ | ︙ | |||
338 339 340 341 342 343 344 | input.money { text-align: right; } input.money + b { padding: .2rem .6rem; line-height: 1.5rem; | | > | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 | input.money { text-align: right; } input.money + b { padding: .2rem .6rem; line-height: 1.5rem; color: var(--gBorderColor); } p.submit { margin: 1em; } form .checkUncheck { float: left; } form span.password_check { margin-left: 1em; padding: .1em .3em; border-radius: .5em; color: #000; } form span.password_check.fail { background-color: #f99; } form span.password_check.weak { background-color: #ff9; } form span.password_check.medium { background-color: #ccf; } form span.password_check.ok { background-color: #cfc; } |
︙ | ︙ | |||
449 450 451 452 453 454 455 | border-radius: .5em; } .datepicker input { font-family: gicon; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 | border-radius: .5em; } .datepicker input { font-family: gicon; } fieldset.memberMessage { max-width: 30em; } fieldset.memberMessage #f_sujet, fieldset.memberMessage #f_message, fieldset.memberMessage select, #queryBuilderForm textarea { width: calc(100% - 2em); } |
︙ | ︙ | |||
600 601 602 603 604 605 606 | max-height: 5em; } .file-selector table.list .num { text-align: right; } | > > > > > > | > | > | | | > > > > > > > > > > > > > > > > > > > > > | 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 | max-height: 5em; } .file-selector table.list .num { text-align: right; } /** * Progress spinner */ .progressing { position: relative; } fieldset.progressing > dl, fieldset.progressing > p { opacity: 0.5; filter: blur(3px); } .progressing::after { display: inline-block; content: " "; position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto; width: 50px; height: 50px; border: 5px solid #666; border-radius: 50%; border-top-color: #ccc; animation: spin 1s ease-in-out infinite; filter: none; } .progress-status { display: none; } .progressing .progress-status { display: inline-block; position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto; padding-top: 80px; text-align: center; width: 100%; height: 1em; filter: none !important; color: #000; } @keyframes spin { to { transform: rotate(360deg); } } @media screen and (max-width: 1279px) { #queryBuilder table tr { display: flex; |
︙ | ︙ |
Modified src/www/admin/static/styles/04-dialogs.css from [0eac2544ce] to [e8d4e068e3].
1 2 3 4 5 6 7 8 9 10 11 | body.transparent { background: none; } html.dialog body { background: transparent; overflow: auto; } html.dialog { height: auto; | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | body.transparent { background: none; } html.dialog body { background: transparent; overflow: auto; } html.dialog { height: auto; background: rgb(var(--gBgColor)); } html.dialog main { background: rgb(var(--gBgColor)); padding: .5em; margin: 0; } /** Dialogs pop-ins */ #dialog { width: 100%; |
︙ | ︙ | |||
70 71 72 73 74 75 76 | opacity: 1; } #dialog > button.closeBtn { background: unset; border: unset; box-shadow: unset; | | | < | 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 101 102 103 104 105 106 | opacity: 1; } #dialog > button.closeBtn { background: unset; border: unset; box-shadow: unset; color: #999; font-size: 1.3em; display: block; width: 90%; } #dialog > button.closeBtn:hover { color: #fff !important; } .loader { width: 100%; min-height: 32px; display: block; position: relative; } .loader.install { margin-top: -40px; } .loader b { text-shadow: 2px 2px 5px #999; background: rgba(255, 255, 255, 0.5); border-radius: .5em; font-size: 16px; line-height: 16px; height: 16px; z-index: 9999; position: absolute; |
︙ | ︙ |
Modified src/www/admin/static/styles/05-navigation.css from [d3ea311406] to [1424a8a273].
︙ | ︙ | |||
29 30 31 32 33 34 35 | } nav.tabs li a { display: inline-block; background: rgba(var(--gSecondColor), .5); border-radius: .5em .5em 0 0; padding: .1em .5em; | | | > | 29 30 31 32 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 | } nav.tabs li a { display: inline-block; background: rgba(var(--gSecondColor), .5); border-radius: .5em .5em 0 0; padding: .1em .5em; color: rgb(var(--gTextColor)); text-decoration: none; transition: background-color .2s, color .2s; } nav.tabs .current a { background: rgb(var(--gMainColor)); color: rgb(var(--gBgColor)); } nav.tabs li a:hover { color: rgb(var(--gBgColor)); background-color: rgb(var(--gMainColor)); text-decoration: underline; border-bottom: none; } nav.tabs aside { float: right; max-width: 50%; text-align: right; clear: right; } |
Modified src/www/admin/static/styles/06-tables.css from [30c2ec2452] to [1bbe7e128c].
1 2 3 4 5 6 7 8 9 10 11 12 | table.list { margin-bottom: 1em; width: 100%; } table.list caption { text-align: center; font-size: 1.2em; } table.list tbody td.desc { font-size: .9em; | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | table.list { margin-bottom: 1em; width: 100%; } table.list caption { text-align: center; font-size: 1.2em; } table.list tbody td.desc { font-size: .9em; color: var(--gBorderColor); } table.list.auto { width: auto; } table.list table { |
︙ | ︙ | |||
43 44 45 46 47 48 49 | transition: background .2s } table.list tr:nth-child(even), table.multi tbody:nth-child(even) { background: rgba(var(--gSecondColor), 0.2); } | < < < < | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | transition: background .2s } table.list tr:nth-child(even), table.multi tbody:nth-child(even) { background: rgba(var(--gSecondColor), 0.2); } table.multi tr { background: inherit !important; } table.list tr.checked { color: #633; background: #ffc; |
︙ | ︙ | |||
79 80 81 82 83 84 85 | } table.list .check { width: 1%; } table.search th { | < < > | < | | 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 101 102 103 104 105 106 107 108 109 110 111 | } table.list .check { width: 1%; } table.search th { background: rgba(var(--gSecondColor), 0.5); } table.list .disabled { color: var(--gBorderColor); background: var(--gLightBorderColor); } .userOrder .cur { background: rgba(var(--gSecondColor), 1.0); color: rgb(var(--gBgColor)); } .userOrder a { text-decoration: none; display: block; color: inherit; padding: .2em; border-radius: .5em; } .userOrder a:hover { background: rgba(var(--gBgColor), 0.5); } table.list .userOrder td, table.list .userOrder th { padding: .2em; } table.list .userOrder .check { |
︙ | ︙ | |||
126 127 128 129 130 131 132 | width: 1em; text-align: center; vertical-align: middle; font-weight: normal; } thead .cur .icn { | | | | | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | width: 1em; text-align: center; vertical-align: middle; font-weight: normal; } thead .cur .icn { color: rgb(var(--gBgColor)); } table.list .actions { text-align: right; } table.list .separator { border-left: 2px dashed #999; } table.list .icon { width: 1.5em; color: rgba(var(--gTextColor), 0.3); } table.list .folder .icon { color: rgba(var(--gTextColor), 0.5); } |
Modified src/www/admin/static/styles/10-accounting.css from [1b7cf590bb] to [432930b788].
︙ | ︙ | |||
22 23 24 25 26 27 28 | } .transaction-lines input[type=text] { min-width: 0 !important; } nav.acc-year { | > | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | } .transaction-lines input[type=text] { min-width: 0 !important; } nav.acc-year { color: rgb(var(--gTextColor)); background: rgb(var(--gBgColor)); text-align: center; border-radius: .5rem; border: .2rem solid rgba(var(--gMainColor), 0.5); display: flex; align-items: center; margin-bottom: .5rem; } |
︙ | ︙ | |||
69 70 71 72 73 74 75 | color: rgb(var(--gMainColor)); } .year-header { text-align: center; margin-bottom: .8em; padding-bottom: .5em; | | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | color: rgb(var(--gMainColor)); } .year-header { text-align: center; margin-bottom: .8em; padding-bottom: .5em; border-bottom: 1pt solid var(--gBorderColor); } .year-header .print-btn button { font-size: 1.3rem; } .year-header form { |
︙ | ︙ |
Modified src/www/admin/static/styles/config.css from [33fa4a39f3] to [cd8a35a686].
1 2 3 4 5 6 7 | .error .trace { border: 1px solid #ccc; margin: 1em; } .error .trace h4 { background: #ccc; | > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 | .error { background: #fff; color: #000; } .error .trace { border: 1px solid #ccc; margin: 1em; } .error .trace h4 { background: #ccc; |
︙ | ︙ |
Modified src/www/admin/static/styles/wiki.css from [5b5f5a2486] to [8d582848fc].
︙ | ︙ | |||
20 21 22 23 24 25 26 | .web-edit { display: block; } } #encryptPasswordDisplay { cursor: help; | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | .web-edit { display: block; } } #encryptPasswordDisplay { cursor: help; background: var(--gLightBackgroundColor); } fieldset.wikiEncrypt, fieldset.wikiMain, .web-edit p.submit { grid-column: 2; } .web-edit dd.help { |
︙ | ︙ | |||
47 48 49 50 51 52 53 | .wikiFiles { text-align: center; } .wikiFooter, .wikiFiles { font-size: 0.8em; | | | < < < < < < < < < < < < < < < < < < < < < < | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | .wikiFiles { text-align: center; } .wikiFooter, .wikiFiles { font-size: 0.8em; color: var(--gBorderColor); border-top: 0.1em solid var(--gLightBorderColor); clear: both; } form#f_upload fieldset { position: relative; } .diff { margin: 1em; } |
︙ | ︙ |
Modified src/www/admin/web/_syntax_markdown.html from [cb696910b0] to [602dc80a26].
︙ | ︙ | |||
15 16 17 18 19 20 21 22 23 24 25 26 27 28 | h5 { font-size: 0.9em; } h6 { font-size: 0.8em; } article, aside, figure, footer, header, hgroup, menu, nav, section { display: block; } body { font-family: "Trebuchet MS", Arial, Helvetica, Sans-serif; padding: .8em; } pre, samp { display: block; background: #ccc; color: #000; border-radius: .5em; padding: .4em; | > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | h5 { font-size: 0.9em; } h6 { font-size: 0.8em; } article, aside, figure, footer, header, hgroup, menu, nav, section { display: block; } body { font-family: "Trebuchet MS", Arial, Helvetica, Sans-serif; padding: .8em; background: #eee; } pre, samp { display: block; background: #ccc; color: #000; border-radius: .5em; padding: .4em; |
︙ | ︙ |
Modified src/www/admin/web/_syntax_skriv.html from [a383e52cdf] to [8451d4b45e].
︙ | ︙ | |||
15 16 17 18 19 20 21 22 23 24 25 26 27 28 | h5 { font-size: 0.9em; } h6 { font-size: 0.8em; } article, aside, figure, footer, header, hgroup, menu, nav, section { display: block; } body { font-family: "Trebuchet MS", Arial, Helvetica, Sans-serif; padding: .8em; } pre, samp { display: block; background: #ccc; color: #000; border-radius: .5em; padding: .4em; | > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | h5 { font-size: 0.9em; } h6 { font-size: 0.8em; } article, aside, figure, footer, header, hgroup, menu, nav, section { display: block; } body { font-family: "Trebuchet MS", Arial, Helvetica, Sans-serif; padding: .8em; background: #eee; } pre, samp { display: block; background: #ccc; color: #000; border-radius: .5em; padding: .4em; |
︙ | ︙ |
Modified src/www/admin/web/page.php from [7684223213] to [fa91cc041f].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php namespace Garradin; use Garradin\Web\Web; use Garradin\Entities\Web\Page; require_once __DIR__ . '/_inc.php'; $page = Web::get(qg('p')); if (!$page) { throw new UserException('Page inconnue'); } | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php namespace Garradin; use Garradin\Web\Web; use Garradin\Entities\Web\Page; require_once __DIR__ . '/_inc.php'; if (!qg('p')) { throw new UserException('Page inconnue'); } $page = Web::get(qg('p')); if (!$page) { throw new UserException('Page inconnue'); } |
︙ | ︙ |