Compare commits

...

120 commits

Author SHA1 Message Date
maxpozdeev
c2ff9a8a7d + Add "Any tag" filter in tag cloud (GH-127) 2026-02-12 22:00:16 +03:00
maxpozdeev
c1467a72b1 Revert "+ can use mid: URL scheme in markdown links (GH-126)"
This reverts commit 1c86b1f606.
2026-02-12 19:35:21 +03:00
maxpozdeev
6b82fc2082 * rewrite titleMarkup() to be able to be redefined by extension 2026-02-12 19:34:47 +03:00
maxpozdeev
768cb550d6 - fix for e00ae3d 2026-01-29 16:03:50 +03:00
maxpozdeev
1c86b1f606 + can use mid: URL scheme in markdown links (GH-126) 2026-01-03 18:27:46 +03:00
maxpozdeev
6f5f329c12 - fix: unable to use 'j M Y ' short date format in duedate picker (closes GH-128) 2026-01-03 18:25:56 +03:00
maxpozdeev
0d1da0db87 - fix: incompatibility with postgesql while export to ical/csv/rss (closes GH-125) 2026-01-03 15:09:06 +03:00
maxpozdeev
e00ae3d1dd * avoid sqlite deprecation notices in PHP 8.5 2026-01-03 14:24:04 +03:00
Max Pozdeev
d0b19e59a6
* Update ZH-CN and ZH-TW Chinese translations (thanks to @wangyouworld)
Simplified and Traditional Chinese Translation based on v1.8.2
2025-07-23 14:38:15 +03:00
wangyouworld
f40b40f030 Simplified and Traditional Chinese Translation based on v1.8.2(file with 4-space indentation) 2025-07-23 09:13:34 +08:00
maxpozdeev
9403d1214a add script for emergency password reset 2025-06-25 15:31:24 +03:00
maxpozdeev
1c27df9b32 set version to 1.8.3 2025-05-29 18:07:03 +03:00
maxpozdeev
3ce7d21df9 update percentage of translations done 2025-05-29 17:51:22 +03:00
maxpozdeev
25f4818d2e - fix: incompatibility with SessionUpdateTimestampHandlerInterface in PHP 7.x 2025-05-29 17:44:58 +03:00
maxpozdeev
9c020ded6d - fix: escaped special html symbols in browser page title (closes GH-113) 2025-05-29 10:18:34 +03:00
maxpozdeev
71b325f389 update Dutch (nl) translation (thanks to J.C.Barnhoorn) 2025-05-17 15:21:37 +03:00
maxpozdeev
ce5491ea1c do not use string_agg in sqlite due to not implemented in old lib versions (like php docker images) 2025-05-13 11:14:40 +03:00
maxpozdeev
9e5ee4f65b update symfony/polyfill-intl-normalizer to v1.32 2025-05-13 09:55:23 +03:00
maxpozdeev
3286f4e78a update percentage of translations done 2025-05-13 09:29:40 +03:00
maxpozdeev
3acf78b77e * Remove restriction on having some characters (<, >, &, ', ") in list names (closes GH-108) 2025-05-12 15:52:24 +03:00
maxpozdeev
ff53d7e443 - Bugfix: no list name in all tasks list after task edit (closes GH-110) 2025-05-12 15:36:20 +03:00
maxpozdeev
b589fcbdb5 use MTTExtensionLoaderException while loading extensions 2025-05-12 15:22:34 +03:00
maxpozdeev
30e6d8c5ae + can use own markdown converter with MTTMarkdown::setInstanceClass 2025-05-12 15:03:08 +03:00
maxpozdeev
0c451ee8ee add get_filever() 2025-04-08 00:03:30 +03:00
maxpozdeev
d34378032f add theme_scripts action and link_css_dark id 2025-04-08 00:02:43 +03:00
maxpozdeev
302a827eca * fix background color of inputs in mobile settings 2025-04-05 20:35:19 +03:00
maxpozdeev
5346491f37 change array_is_list polyfill 2025-04-04 01:27:09 +03:00
maxpozdeev
42baf175aa fix: extensions were not loaded due to non-list storage 2025-04-04 01:26:38 +03:00
maxpozdeev
1c30cf12d1 update COPYRIGHT file 2025-03-11 12:26:17 +03:00
maxpozdeev
7f84eaa713 add Estonian translation (thanks to Rivo Zängov) 2025-03-03 21:29:10 +03:00
maxpozdeev
591f1ca11c fix prev commit 2025-03-03 20:38:51 +03:00
maxpozdeev
a4635a1933 more checks of arrays 2025-03-03 15:09:14 +03:00
maxpozdeev
70d3e08c11 * do not write session data on every request 2025-02-27 21:34:32 +03:00
maxpozdeev
0679aa53eb remove unused tag 2025-02-26 18:53:31 +03:00
maxpozdeev
58642b9535 - Fix missing task's list name in All Tasks list after task was moved to another list (GH-107) 2025-02-25 22:09:23 +03:00
maxpozdeev
4c2033aa8c - Fix incorrect list name in task viewer opened from All tasks list (GH-107) 2025-02-25 21:46:11 +03:00
maxpozdeev
4356dd2c62 - dont show edit task button in taskviewer in readonly mode 2025-02-23 23:26:25 +03:00
maxpozdeev
dd4c38438b * better handling of auto_increment in backup extension 2025-02-23 22:12:08 +03:00
maxpozdeev
ac1df904ca update .htaccess 2025-02-21 22:18:46 +03:00
maxpozdeev
8e926b1208 update the percentage of translation completeness 2025-02-21 19:09:08 +03:00
maxpozdeev
7754719702 + Can filter tags in tag cloud (GH-105) 2025-02-21 12:20:27 +03:00
maxpozdeev
722a0a401c fix typo 2025-02-21 10:42:54 +03:00
maxpozdeev
99afe12cba Use randomString in setup for csrf token 2025-02-20 18:29:04 +03:00
maxpozdeev
846b4222fe - Fix: unable to upgrade old setups with db v1.4 with password protection 2025-02-20 17:28:47 +03:00
maxpozdeev
2841e12a30 * Batch of small UI changes 2025-02-19 22:38:55 +03:00
maxpozdeev
f7a7294466 Update jQuery UI to v1.14.1 2025-02-19 18:42:29 +03:00
maxpozdeev
0a093d4029 Merge branch 'master' of git@github.com:maxpozdeev/mytinytodo.git 2025-02-18 22:38:19 +03:00
Max Pozdeev
81a2dc6981
Add sys reqs to README.md 2025-02-18 22:37:37 +03:00
maxpozdeev
c7f935f1c8 Update jQuery UI Touch Punch to 1.1.5 with my patches 2025-02-17 22:17:25 +03:00
maxpozdeev
b6a6bc0ca4 add comments to avoid notices in ide 2025-02-17 12:31:10 +03:00
maxpozdeev
8082278af5 + Can filter tasks by having any tag or not having tags (closes GH-64) 2025-02-17 12:30:30 +03:00
maxpozdeev
4548aa17de Set version to 1.8.2 2025-02-16 18:40:42 +03:00
maxpozdeev
5cbe0d93a7 Added info about percent of translations completion 2025-02-16 18:28:56 +03:00
Max Pozdeev
510d04c48f
Merge pull request #100 from AlainRnet/patch-1
Update fr translation (thanks @AlainRnet)
2025-02-16 18:26:01 +03:00
maxpozdeev
360661f002 Restore authors history in zh-cn translation 2025-02-16 14:41:49 +03:00
maxpozdeev
0a56396091 Fix tabs in ru,en 2025-02-16 14:27:29 +03:00
maxpozdeev
a2b472f2d8 + Show counters of new tasks in the Select List menu 2025-02-16 00:27:50 +03:00
maxpozdeev
c11b7f5b34 + Can show a counter of new tasks as a favicon (GH-5, GH-25) 2025-02-15 21:50:09 +03:00
maxpozdeev
b05f40f77c Move js call of tasks/newCounter to js api file 2025-02-15 20:37:54 +03:00
maxpozdeev
30b08bd87c update .gitignore 2025-02-15 13:34:24 +03:00
maxpozdeev
2cbc827bca remove dev docker files 2025-02-15 13:34:03 +03:00
maxpozdeev
6b5c8221de add xml to .editorconfig 2025-02-15 13:18:24 +03:00
maxpozdeev
430de1793c little refactoring in updater extension 2025-02-09 01:08:22 +03:00
maxpozdeev
9bcb0cb7b1 Update Parsedown 1.7.4 to remove deprecation notice in PHP 8.4 2025-02-08 23:44:25 +03:00
maxpozdeev
96aaba10aa do not use E_STRICT 2025-02-05 23:49:13 +03:00
maxpozdeev
49b02cd4f8 - Fix empty page while print in firefox (closes GH-103) 2025-02-01 23:56:24 +03:00
maxpozdeev
c611762c9e - Fix margin of title in print style 2025-02-01 23:08:14 +03:00
maxpozdeev
2b5f31dab0 Fix authors and duplicates in French translation 2025-02-01 21:36:56 +03:00
Max Pozdeev
57681c8390
Merge pull request #83 from wangyouworld/master
Update zh-cn translation (thanks @wangyouworld GH-83)
2025-01-30 20:25:19 +03:00
maxpozdeev
7136e9f26c Fix indentation for easy diff 2025-01-30 20:22:01 +03:00
maxpozdeev
f952ddc130 add types to url_dir() definition 2025-01-21 16:16:27 +03:00
maxpozdeev
3ddd6d6ee4 can log sql queries to file 2025-01-20 00:35:22 +03:00
maxpozdeev
b0a104ea01 more strictness 2025-01-19 23:43:23 +03:00
maxpozdeev
6b97296251 update libs 2025-01-19 22:35:43 +03:00
maxpozdeev
b7d9cf08a0 can use podman for composer 2025-01-19 22:30:50 +03:00
Alain Rihs
f461a16d65
Update fr.json
from v1.6.8 to v1.8.1
2024-12-10 11:07:57 +01:00
maxpozdeev
a4cc7f4e40 - fix deprecation notice in PHP 8.4 2024-08-14 23:01:19 +03:00
Max Pozdeev
7ec5108e22
Merge pull request #89 from dennykorsukewitz/pr-language-de
Updated de language file, thanks to Denny Korsukéwit @dennykorsukewitz (GH-89)
2024-08-14 15:19:11 +03:00
maxpozdeev
cd38503951 * Add german localization for Notifications and Updater extensions (thanks to Daniel Schlapa @Dtrieb) (GH-92 GH-93) 2024-08-11 12:36:53 +03:00
maxpozdeev
22f3dab70d normalize ext loader func to be able to have '-' in ext directory name 2024-08-10 20:01:04 +03:00
Denny Korsukéwitz
d35684f861 Updated de language file via myTinyTodo translation maker v2.1. 2024-04-03 22:45:24 +02:00
maxpozdeev
dde725d06d add Y38 notice 2024-02-05 00:02:38 +03:00
maxpozdeev
80de4b7a9b + add setting for counter of new tasks (disabled by default) (2 strings added for translation) 2024-01-23 13:35:19 +03:00
maxpozdeev
34e8421435 UI groups in notifications extension 2024-01-19 17:00:32 +03:00
maxpozdeev
700e58e3dc can set MTT_DEBUG constant in config file 2024-01-08 13:39:56 +03:00
maxpozdeev
454eef2e07 Revert "* do not strikethrough completed tasks"
This reverts commit bad99a11ab.
2024-01-08 13:11:24 +03:00
maxpozdeev
87620921a2 css for groups in settings 2024-01-08 13:06:45 +03:00
maxpozdeev
3f721aa1cf little more debug info in setup 2024-01-07 14:24:03 +03:00
maxpozdeev
634cdcceee - bugfix: failed to upgrade db v1.4 due to unnecessary db request (GH-85) 2024-01-07 14:23:31 +03:00
wangyouworld
29d9da73bb
v1.8.0 zh_cn latest translation files 2024-01-02 16:42:36 +08:00
maxpozdeev
33bb209b97 - fix backup ext date format (minute) 2023-12-26 13:03:41 +03:00
maxpozdeev
081c1a94fe ext can alert on settings page refresh 2023-12-26 13:01:01 +03:00
maxpozdeev
9191031140 backup extension shows alerts on check and repair inconsistency actions 2023-12-26 12:36:04 +03:00
maxpozdeev
39ba94e303 * ext action can show alert on result 2023-12-26 12:34:22 +03:00
maxpozdeev
273ceca063 Merge branch 'master' of github.com:maxpozdeev/mytinytodo 2023-12-18 12:39:10 +03:00
Max Pozdeev
39790f01dd
Merge pull request #80 from toddy15/main
Update German translation
2023-12-18 12:34:53 +03:00
Dr. Tobias Quathamer
8e45ceaa3a Update German translation 2023-12-17 23:20:12 +01:00
maxpozdeev
f31b97c4c7 check for posix module in nottifications extension 2023-12-17 17:45:04 +03:00
maxpozdeev
7058769c96 update dev docker for php 8.3 2023-12-02 15:46:48 +03:00
maxpozdeev
d3e4286380 set version to 1.8.1 2023-12-02 14:31:39 +03:00
maxpozdeev
b721ca9b33 * do not highlight a task on hover in tasklist 2023-12-02 14:27:33 +03:00
maxpozdeev
b4703b29f8 - fix: alltasks tab was not filled if new list with tasks was created in another session 2023-12-02 14:13:39 +03:00
maxpozdeev
dd27362e96 - fix: counter of new tasks was not displayed due to incorrect list ref 2023-12-02 00:53:58 +03:00
maxpozdeev
7b84cdabf6 set version to 1.8.0 2023-11-23 23:18:40 +03:00
maxpozdeev
9c4087fe38 - handle more area to start manual sorting of tasks 2023-11-23 23:18:24 +03:00
maxpozdeev
691a99cb28 + can use manual sorting in reverse order (i.e. new tasks are on top) 2023-11-23 23:16:40 +03:00
maxpozdeev
dfe908776e little refactoring of js api driver 2023-11-23 21:51:54 +03:00
maxpozdeev
17c8cf87d6 * replace last float with flex in css 2023-11-09 23:07:45 +03:00
maxpozdeev
edfe391e41 * add more compatibility for http api (able to use GET and POST requests only) 2023-11-04 14:58:24 +03:00
maxpozdeev
b7e060e6db better css for RTL localisations 2023-10-18 15:57:18 +03:00
maxpozdeev
146d9a19bb better css for RTL localisations 2023-10-09 11:10:26 +03:00
maxpozdeev
ae6a4ef2a4 - fix: new tasks counter was not working in old browsers (like chrome 49) due to the absent cookies in fetch 2023-10-09 11:09:17 +03:00
maxpozdeev
9a1970d3b1 * use link media instead of js for auto and compulsory dark mode 2023-10-09 11:07:34 +03:00
maxpozdeev
9489e51574 * add ability to select month and year in due date picker 2023-10-04 23:17:34 +03:00
maxpozdeev
0b743618ea * disable preview by tag 2023-10-01 21:52:41 +03:00
maxpozdeev
6eac80ee1d set version to 1.8-beta2 2023-09-27 15:13:40 +03:00
maxpozdeev
e446880836 - fix: counter of new tasks was not reset when tasks were completed 2023-09-27 14:14:16 +03:00
maxpozdeev
5b9e142f89 exclude xattrs while build tar 2023-09-17 16:30:48 +03:00
maxpozdeev
1efbe606fd - fix: new tasks counter failed for newly created lists 2023-09-17 16:15:23 +03:00
maxpozdeev
ab9f398d7b - fix tab counter failed if only one tab open 2023-09-15 23:58:50 +03:00
135 changed files with 2492 additions and 2312 deletions

View file

@ -19,7 +19,7 @@ indent_size = 4
indent_style = space
tab_width = 4
[*.{css,yml,html,svg}]
[*.{css,yml,html,svg,xml}]
indent_style = space
indent_size = 2

2
.gitignore vendored
View file

@ -1,6 +1,8 @@
.DS_Store
src/db/todolist.db*
src/db/config.php
src/db/config-*
src/db/backup.xml*
src/config.php
src/includes/vendor/
src/content/theme/custom.css

View file

@ -1,3 +1,22 @@
myTinyTodo
# myTinyTodo
Your tiny todo list
Original website - http://www.mytinytodo.net/
### System requirements
- PHP 7.2 or greater
- PHP extensions:
- mbstring
- pdo_sqlite, intl (SQLite version)
- pdo_mysql or mysqli (MySQL version)
- pdo_pgsql (PostgreSQL version)
- One of databases:
- MySQL 5.7 or greater / MariaDB 10.2 or greater
- PostgreSQL 10 or greater
- SQLite (system library)
Supported browsers: Chrome 49, Safari 10, Firefox 53.
Internet Explorer and Opera with Presto engine are not supported.

View file

@ -43,7 +43,9 @@ print "> Version is $ver\n";
unlink('./docker-config.php');
unlink('./includes/lang/en-rtl.json');
unlink('./includes/lang/_percent.php');
unlink('./mtt-edit-settings.php');
unlink('./mtt-emergency.php');
unlink('./content/theme/images/svg2base64.php');
chdir('..'); # to the root of repo
@ -70,7 +72,7 @@ if (is_dir('src/ext')) {
}
chdir('../ext2');
if ($extCount > 0) {
`tar -czf ../ext/extensions.tar.gz *`; #OS dep.!!!
`tar --no-xattrs -czf ../ext/extensions.tar.gz *`; #OS dep.!!!
}
chdir('../..');
deleteTreeIfDir('src/ext2');
@ -80,7 +82,7 @@ if (is_dir('src/ext')) {
rename('src', 'mytinytodo') or die("Cant rename 'src'\n");
`tar -czf mytinytodo.tar.gz mytinytodo`; #OS dep.!!!
`tar --no-xattrs -czf mytinytodo.tar.gz mytinytodo`; #OS dep.!!!
if (!file_exists('mytinytodo.tar.gz')) {
die("Failed to pack files (no output tar.gz file)\n");
}

View file

@ -1,12 +1,24 @@
{
"name": "maxpozdeev/mytinytodo",
"type": "project",
"license": "GPL-2.0-or-later",
"homepage": "https://mytinytodo.net",
"authors": [
{
"name": "Max Pozdeev",
"role": "Developer"
}
],
"config": {
"vendor-dir": "src/includes/vendor"
},
"require": {
"erusev/parsedown": "^1.7",
"symfony/polyfill-intl-normalizer": "^1.28"
"php": ">=7.2",
"ext-mbstring": "*",
"erusev/parsedown": "1.7.x-dev#f7285e7",
"symfony/polyfill-intl-normalizer": "^1.31"
},
"require-dev": {
"league/commonmark": "^2.4"
"league/commonmark": "^2.6"
}
}

165
composer.lock generated
View file

@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "ee0f5e5f2fe7aba230dbdcace19801b2",
"content-hash": "c27d4b183be86ec7d95203f1a84b86e2",
"packages": [
{
"name": "erusev/parsedown",
"version": "1.7.4",
"version": "1.7.x-dev",
"source": {
"type": "git",
"url": "https://github.com/erusev/parsedown.git",
"reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3"
"reference": "f7285e7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/f7285e7",
"reference": "f7285e7",
"shasum": ""
},
"require": {
@ -25,7 +25,7 @@
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
"phpunit/phpunit": "^4.8|^5.7|^6.5|^7.5|^8.5|^9.6"
},
"type": "library",
"autoload": {
@ -54,36 +54,33 @@
"issues": "https://github.com/erusev/parsedown/issues",
"source": "https://github.com/erusev/parsedown/tree/1.7.x"
},
"time": "2019-12-30T22:54:17+00:00"
"time": "2024-07-12T14:59:16+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.28.0",
"version": "v1.32.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92"
"reference": "3833d7255cc303546435cb650316bff708a1c75c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
"reference": "3833d7255cc303546435cb650316bff708a1c75c",
"shasum": ""
},
"require": {
"php": ">=7.1"
"php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
@ -122,7 +119,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
},
"funding": [
{
@ -138,22 +135,22 @@
"type": "tidelift"
}
],
"time": "2023-01-26T09:26:14+00:00"
"time": "2024-09-09T11:45:10+00:00"
}
],
"packages-dev": [
{
"name": "dflydev/dot-access-data",
"version": "v3.0.2",
"version": "v3.0.3",
"source": {
"type": "git",
"url": "https://github.com/dflydev/dflydev-dot-access-data.git",
"reference": "f41715465d65213d644d3141a6a93081be5d3549"
"reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/f41715465d65213d644d3141a6a93081be5d3549",
"reference": "f41715465d65213d644d3141a6a93081be5d3549",
"url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/a23a2bf4f31d3518f3ecb38660c95715dfead60f",
"reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f",
"shasum": ""
},
"require": {
@ -213,22 +210,22 @@
],
"support": {
"issues": "https://github.com/dflydev/dflydev-dot-access-data/issues",
"source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.2"
"source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.3"
},
"time": "2022-10-27T11:44:00+00:00"
"time": "2024-07-08T12:26:09+00:00"
},
{
"name": "league/commonmark",
"version": "2.4.1",
"version": "2.7.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/commonmark.git",
"reference": "3669d6d5f7a47a93c08ddff335e6d945481a1dd5"
"reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/3669d6d5f7a47a93c08ddff335e6d945481a1dd5",
"reference": "3669d6d5f7a47a93c08ddff335e6d945481a1dd5",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/6fbb36d44824ed4091adbcf4c7d4a3923cdb3405",
"reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405",
"shasum": ""
},
"require": {
@ -241,8 +238,8 @@
},
"require-dev": {
"cebe/markdown": "^1.0",
"commonmark/cmark": "0.30.0",
"commonmark/commonmark.js": "0.30.0",
"commonmark/cmark": "0.31.1",
"commonmark/commonmark.js": "0.31.1",
"composer/package-versions-deprecated": "^1.8",
"embed/embed": "^4.4",
"erusev/parsedown": "^1.0",
@ -251,10 +248,11 @@
"michelf/php-markdown": "^1.4 || ^2.0",
"nyholm/psr7": "^1.5",
"phpstan/phpstan": "^1.8.2",
"phpunit/phpunit": "^9.5.21",
"phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0",
"scrutinizer/ocular": "^1.8.1",
"symfony/finder": "^5.3 | ^6.0",
"symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0",
"symfony/finder": "^5.3 | ^6.0 | ^7.0",
"symfony/process": "^5.4 | ^6.0 | ^7.0",
"symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0",
"unleashedtech/php-coding-standard": "^3.1.1",
"vimeo/psalm": "^4.24.0 || ^5.0.0"
},
@ -264,7 +262,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "2.5-dev"
"dev-main": "2.8-dev"
}
},
"autoload": {
@ -321,7 +319,7 @@
"type": "tidelift"
}
],
"time": "2023-08-30T16:55:00+00:00"
"time": "2025-05-05T12:20:28+00:00"
},
{
"name": "league/config",
@ -407,31 +405,31 @@
},
{
"name": "nette/schema",
"version": "v1.2.4",
"version": "v1.3.2",
"source": {
"type": "git",
"url": "https://github.com/nette/schema.git",
"reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab"
"reference": "da801d52f0354f70a638673c4a0f04e16529431d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/schema/zipball/c9ff517a53903b3d4e29ec547fb20feecb05b8ab",
"reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab",
"url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d",
"reference": "da801d52f0354f70a638673c4a0f04e16529431d",
"shasum": ""
},
"require": {
"nette/utils": "^2.5.7 || ^3.1.5 || ^4.0",
"php": "7.1 - 8.3"
"nette/utils": "^4.0",
"php": "8.1 - 8.4"
},
"require-dev": {
"nette/tester": "^2.3 || ^2.4",
"nette/tester": "^2.5.2",
"phpstan/phpstan-nette": "^1.0",
"tracy/tracy": "^2.7"
"tracy/tracy": "^2.8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
"dev-master": "1.3-dev"
}
},
"autoload": {
@ -463,26 +461,26 @@
],
"support": {
"issues": "https://github.com/nette/schema/issues",
"source": "https://github.com/nette/schema/tree/v1.2.4"
"source": "https://github.com/nette/schema/tree/v1.3.2"
},
"time": "2023-08-05T18:56:25+00:00"
"time": "2024-10-06T23:10:23+00:00"
},
{
"name": "nette/utils",
"version": "v4.0.1",
"version": "v4.0.6",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
"reference": "9124157137da01b1f5a5a22d6486cb975f26db7e"
"reference": "ce708655043c7050eb050df361c5e313cf708309"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/9124157137da01b1f5a5a22d6486cb975f26db7e",
"reference": "9124157137da01b1f5a5a22d6486cb975f26db7e",
"url": "https://api.github.com/repos/nette/utils/zipball/ce708655043c7050eb050df361c5e313cf708309",
"reference": "ce708655043c7050eb050df361c5e313cf708309",
"shasum": ""
},
"require": {
"php": ">=8.0 <8.4"
"php": "8.0 - 8.4"
},
"conflict": {
"nette/finder": "<3",
@ -500,8 +498,7 @@
"ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
"ext-json": "to use Nette\\Utils\\Json",
"ext-mbstring": "to use Strings::lower() etc...",
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()",
"ext-xml": "to use Strings::length() etc. when mbstring is not available"
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()"
},
"type": "library",
"extra": {
@ -550,9 +547,9 @@
],
"support": {
"issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v4.0.1"
"source": "https://github.com/nette/utils/tree/v4.0.6"
},
"time": "2023-07-30T15:42:21+00:00"
"time": "2025-03-30T21:06:30+00:00"
},
{
"name": "psr/event-dispatcher",
@ -606,16 +603,16 @@
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.3.0",
"version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
"reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
"reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
"shasum": ""
},
"require": {
@ -623,12 +620,12 @@
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.4-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.5-dev"
}
},
"autoload": {
@ -653,7 +650,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0"
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
},
"funding": [
{
@ -669,33 +666,30 @@
"type": "tidelift"
}
],
"time": "2023-05-23T14:45:45+00:00"
"time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.28.0",
"version": "v1.32.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5"
"reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
"reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
"shasum": ""
},
"require": {
"php": ">=7.1"
"php": ">=7.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
@ -736,7 +730,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0"
},
"funding": [
{
@ -752,15 +746,20 @@
"type": "tidelift"
}
],
"time": "2023-01-26T09:26:14+00:00"
"time": "2025-01-02T08:10:11+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {
"erusev/parsedown": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.3.0"
"platform": {
"php": ">=7.2",
"ext-mbstring": "*"
},
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View file

@ -3,4 +3,9 @@
#dir="$( dirname -- "$( readlink -f -- "$0"; )"; )"
dir="$PWD"
docker run -it --rm -v "$dir:/app" composer $@
app=$(which podman)
if [ -z $app ]; then
app="docker"
fi
$app run -it --rm -v "$dir:/app" composer $@

View file

@ -1 +0,0 @@
*/db_data

View file

@ -1,4 +0,0 @@
[mysqld]
collation-server = utf8mb4_unicode_ci
character-set-server = utf8mb4
innodb_log_file_size=10M

View file

@ -1,4 +0,0 @@
[mysqld]
collation-server = utf8mb4_unicode_ci
character-set-server = utf8mb4
innodb_log_file_size=10M

View file

@ -1,4 +0,0 @@
[mysqld]
collation-server = utf8mb4_unicode_ci
character-set-server = utf8mb4
innodb_log_file_size=10M

View file

@ -1,23 +0,0 @@
FROM alpine:latest
RUN set -x \
&& apk add --no-cache ca-certificates curl \
&& curl -o /etc/apk/keys/angie-signing.rsa https://angie.software/keys/angie-signing.rsa \
&& echo "https://download.angie.software/angie/alpine/v$(egrep -o '[0-9]+\.[0-9]+' /etc/alpine-release)/main" >> /etc/apk/repositories \
&& apk add --no-cache angie \
&& rm /etc/apk/keys/angie-signing.rsa \
&& ln -sf /dev/stdout /var/log/angie/access.log \
&& ln -sf /dev/stderr /var/log/angie/error.log
EXPOSE 80
CMD ["angie", "-g", "daemon off;"]
RUN mv /etc/angie/http.d/default.conf /etc/angie/http.d/default.conf.bak \
&& mkdir /var/log/nginx \
&& ln -sf /var/log/angie/access.log /var/log/nginx/access.log
# config from nginx
COPY default.conf /etc/angie/http.d/default.conf
VOLUME /var/www/html

View file

@ -1,5 +0,0 @@
FROM nginx:latest
COPY default.conf /etc/nginx/conf.d/
VOLUME /var/www/html

View file

@ -1,5 +0,0 @@
FROM nginx:alpine
COPY default.conf /etc/nginx/conf.d/
VOLUME /var/www/html

View file

@ -1,59 +0,0 @@
# format like 'main' excluding user agent
log_format mtt '$time_local "$request" $status $body_bytes_sent "$http_referer"';
log_format mtt2 '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer"';
access_log off;
upstream fpm {
server fpm:9000;
}
server {
listen 80;
server_name localhost;
root /var/www/html; # same as php-fpm
access_log /var/log/nginx/access.log mtt;
index index.php index.html;
autoindex off;
location = /phpinfo {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /var/www/phpinfo/phpinfo.php;
fastcgi_pass fpm;
}
location /api/ {
rewrite ^/api/(.*) /api.php/$1 last;
}
location / {
try_files $uri $uri/ =404;
}
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_index index.php;
fastcgi_pass fpm;
}
location /db/ {
return 404; #deny all
}
location /includes/ {
return 404; #deny all
}
location ~ /\.ht {
return 404; #deny all
}
}

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php72-angie-postgres10

View file

@ -1,17 +0,0 @@
FROM php:7.2-fpm-alpine
RUN apk add --update-cache libpq postgresql-dev && \
docker-php-ext-install pdo_mysql pdo_pgsql && \
apk del postgresql-dev && rm -rf /var/cache/apk/* && \
mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" && \
mkdir /var/www/phpinfo && \
echo "<?php phpinfo();" > /var/www/phpinfo/phpinfo.php && \
curl -o /usr/local/bin/phpunit -fL "https://phar.phpunit.de/phpunit-8.phar" && \
chmod +x /usr/local/bin/phpunit && \
ln -s html /var/www/src
COPY php-mtt.ini /usr/local/etc/php/conf.d/
COPY php-opcache.ini /usr/local/etc/php/conf.d/
COPY php-fpm-www.conf /usr/local/etc/php-fpm.d/www.conf
VOLUME /var/www/html

View file

@ -1,58 +0,0 @@
version: "3.9"
networks:
network:
name: "${PLATFORM_NAME}-network"
services:
web:
build:
context: ../_nginx
dockerfile: Dockerfile-angie-alpine
image: mtt-dev/angie:alpine
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
volumes:
- ../../../src:/var/www/html
depends_on:
- fpm
networks:
- network
fpm:
build:
context: .
dockerfile: Dockerfile-fpm
image: mtt-dev/php:7.2-fpm-alpine
container_name: ${PLATFORM_NAME}-fpm
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=postgres
- MTT_API_USE_PATH_INFO=YES
- MTT_DB_HOST=db
- MTT_DB_NAME=mtt
- MTT_DB_USER=mtt
- MTT_DB_PASSWORD=mtt
- MTT_DB_PREFIX=mtt_
volumes:
- ../../../src:/var/www/html
- ../../../tests:/var/www/tests
- ./php-mtt.ini:/usr/local/etc/php/conf.d/php-mtt.ini
- ./php-opcache.ini:/usr/local/etc/php/conf.d/php-opcache.ini
networks:
- network
db:
# do not use alpine image due to missing locales
image: postgres:10.0
container_name: ${PLATFORM_NAME}-db
userns_mode: keep-id
environment:
POSTGRES_PASSWORD: mtt
POSTGRES_USER: mtt
POSTGRES_DB: mtt
volumes:
- ../_postgres10/db_data:/var/lib/postgresql/data
networks:
- network

View file

@ -1,13 +0,0 @@
[www]
user = www-data
group = www-data
listen = 127.0.0.1:9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 500
access.format = "%R - %u [%t] \"%m %r\" %s %f"
access.log = /dev/null

View file

@ -1,10 +0,0 @@

; Since PHP 5.4 E_STRICT is included in E_ALL
error_reporting = E_ALL
log_errors = On
display_errors = On
display_startup_errors = On
cgi.fix_pathinfo=0
session.gc_divisor = 100

View file

@ -1,42 +0,0 @@
;; opcache.ini
;; check /usr/local/etc/php/conf.d if exists docker-php-ext-opcache.ini
; To disable opcache just comment this line
zend_extension=opcache.so
[opcache]
opcache.enable=1
opcache.enable_cli=1
; JIT will work only if opcache is enabled and jit_buffer_size is not zero.
; To disable JIT set the buffer size to 0.
opcache.jit_buffer_size=64M
; JIT mode. Read more at https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.jit
; Default is tracing.
opcache.jit=tracing
; The size of the shared memory storage used by OPcache, in megabytes. The minimum permissible value is "8", which is enforced if a smaller value is set.
; Default is 128.
opcache.memory_consumption=128
; The maximum number of keys (and therefore scripts) in the OPcache hash table.
; The actual value used will be the first number in the set of prime numbers
; { 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 }
; that is greater than or equal to the configured value.
; The minimum value is 200. The maximum value is 1000000. Values outside of this range are clamped to the permissible range.
; Default is 10000.
opcache.max_accelerated_files=1000
; How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.
; This configuration directive is ignored if opcache.validate_timestamps is disabled.
; Default is 2.
opcache.revalidate_freq=2
; If enabled, OPcache will check for updated scripts every opcache.revalidate_freq seconds.
; When this directive is disabled, you must reset OPcache manually via opcache_reset(), opcache_invalidate()
; or by restarting the Web server for changes to the filesystem to take effect.
; Default is 1.
;; Override in docker-compose
opcache.validate_timestamps=1

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php72-apache-mariadb100

View file

@ -1,47 +0,0 @@
version: "3.9"
networks:
network:
name: "${PLATFORM_NAME}-network"
services:
web:
build:
context: ../mtt-php72-apache/
dockerfile: Dockerfile-web
image: mtt-dev/php:7.2-apache
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=mysql
- MTT_DB_HOST=db
- MTT_DB_NAME=mytinytodo
- MTT_DB_USER=mtt
- MTT_DB_PASSWORD=mtt
- MTT_DB_PREFIX=mtt_
- MTT_DB_DRIVER=mysqli
volumes:
- ../../../src:/var/www/html
- ../mtt-php72-apache/php-mtt.ini:/usr/local/etc/php/conf.d/php-mtt.ini
- ../mtt-php72-apache/php-opcache.ini:/usr/local/etc/php/conf.d/php-opcache.ini
depends_on:
- db
networks:
- network
db:
image: mariadb:10.0.15
container_name: ${PLATFORM_NAME}-db
#restart: always
environment:
MYSQL_ROOT_PASSWORD: JustForDev
MYSQL_USER: mtt
MYSQL_PASSWORD: mtt
MYSQL_DATABASE: mytinytodo
volumes:
- ../_mariadb100/my.cnf:/etc/mysql/conf.d/my.cnf
- ../_mariadb100/db_data:/var/lib/mysql
networks:
- network

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php72-apache-mariadb105

View file

@ -1,47 +0,0 @@
version: "3.9"
networks:
network:
name: "${PLATFORM_NAME}-network"
services:
web:
build:
context: ../mtt-php72-apache/
dockerfile: Dockerfile-web
image: mtt-dev/php:7.2-apache
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=mysql
- MTT_DB_HOST=db
- MTT_DB_NAME=mytinytodo
- MTT_DB_USER=mtt
- MTT_DB_PASSWORD=mtt
- MTT_DB_PREFIX=mtt_
- MTT_DB_DRIVER=mysqli
volumes:
- ../../../src:/var/www/html
- ../mtt-php72-apache/php-mtt.ini:/usr/local/etc/php/conf.d/php-mtt.ini
- ../mtt-php72-apache/php-opcache.ini:/usr/local/etc/php/conf.d/php-opcache.ini
depends_on:
- db
networks:
- network
db:
image: mariadb:10.5
container_name: ${PLATFORM_NAME}-db
#restart: always
environment:
MARIADB_ROOT_PASSWORD: JustForDev
MARIADB_USER: mtt
MARIADB_PASSWORD: mtt
MARIADB_DATABASE: mytinytodo
volumes:
- ../_mariadb105/my.cnf:/etc/mysql/conf.d/my.cnf
- ../_mariadb105/db_data:/var/lib/mysql
networks:
- network

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php72-apache-postgres10

View file

@ -1,45 +0,0 @@
version: "3.9"
networks:
network:
name: "${PLATFORM_NAME}-network"
services:
web:
build:
context: ../mtt-php72-apache/
dockerfile: Dockerfile-web
image: mtt-dev/php:7.2-apache
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=postgres
- MTT_DB_HOST=db
- MTT_DB_NAME=mtt
- MTT_DB_USER=mtt
- MTT_DB_PASSWORD=mtt
- MTT_DB_PREFIX=mtt_
volumes:
- ../../../src:/var/www/html
- ../mtt-php72-apache/php-mtt.ini:/usr/local/etc/php/conf.d/php-mtt.ini
- ../mtt-php72-apache/php-opcache.ini:/usr/local/etc/php/conf.d/php-opcache.ini
depends_on:
- db
networks:
- network
db:
# do not use alpine image due to missing locales
image: postgres:10.0
container_name: ${PLATFORM_NAME}-db
userns_mode: keep-id
environment:
POSTGRES_PASSWORD: mtt
POSTGRES_USER: mtt
POSTGRES_DB: mtt
volumes:
- ../_postgres10/db_data:/var/lib/postgresql/data
networks:
- network

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php72-apache

View file

@ -1,18 +0,0 @@
FROM php:7.2-apache-buster
RUN apt-get update && apt-get install -y libpq5 libpq-dev && \
docker-php-ext-install mysqli pdo_pgsql && \
apt-get remove -y libpq-dev && apt-get -y autoremove && \
mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" && \
mkdir /var/www/phpinfo && \
echo "<?php\nphpinfo();" > /var/www/phpinfo/phpinfo.php && \
echo 'Alias "/phpinfo" "/var/www/phpinfo/phpinfo.php"' > /etc/apache2/conf-enabled/phpinfo.conf && \
echo 'LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\"" combined' > /etc/apache2/conf-enabled/logformat.conf && \
a2enmod rewrite && \
curl -o /usr/local/bin/phpunit -fL "https://phar.phpunit.de/phpunit-8.phar" && \
chmod +x /usr/local/bin/phpunit && \
ln -s html /var/www/src
COPY php-mtt.ini /usr/local/etc/php/conf.d/
COPY php-opcache.ini /usr/local/etc/php/conf.d/

View file

@ -1,17 +0,0 @@
services:
web:
build:
context: .
dockerfile: Dockerfile-web
image: mtt-dev/php:7.2-apache
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=sqlite
volumes:
- ../../../src:/var/www/html
- ../../../tests:/var/www/tests
- ./php-mtt.ini:/usr/local/etc/php/conf.d/php-mtt.ini
- ./php-opcache.ini:/usr/local/etc/php/conf.d/php-opcache.ini

View file

@ -1,11 +0,0 @@

; Since PHP 5.4 E_STRICT is included in E_ALL
error_reporting = E_ALL
log_errors = On
display_errors = On
display_startup_errors = On
session.gc_divisor = 100
allow_url_fopen=1

View file

@ -1,34 +0,0 @@
;; opcache.ini
;; check /usr/local/etc/php/conf.d if exists docker-php-ext-opcache.ini
; To disable opcache just comment this line
zend_extension=opcache.so
[opcache]
opcache.enable=0
opcache.enable_cli=0
; The size of the shared memory storage used by OPcache, in megabytes. The minimum permissible value is "8", which is enforced if a smaller value is set.
; Default is 128.
opcache.memory_consumption=128
; The maximum number of keys (and therefore scripts) in the OPcache hash table.
; The actual value used will be the first number in the set of prime numbers
; { 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 }
; that is greater than or equal to the configured value.
; The minimum value is 200. The maximum value is 1000000. Values outside of this range are clamped to the permissible range.
; Default is 10000.
opcache.max_accelerated_files=1000
; How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.
; This configuration directive is ignored if opcache.validate_timestamps is disabled.
; Default is 2.
opcache.revalidate_freq=2
; If enabled, OPcache will check for updated scripts every opcache.revalidate_freq seconds.
; When this directive is disabled, you must reset OPcache manually via opcache_reset(), opcache_invalidate()
; or by restarting the Web server for changes to the filesystem to take effect.
; Default is 1.
;; Override in docker-compose
opcache.validate_timestamps=1

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php74-apache

View file

@ -1,15 +0,0 @@
FROM php:7.4-apache
RUN docker-php-ext-install mysqli && \
mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" && \
mkdir /var/www/phpinfo && \
echo "<?php\nphpinfo();" > /var/www/phpinfo/phpinfo.php && \
echo 'Alias "/phpinfo" "/var/www/phpinfo/phpinfo.php"' > /etc/apache2/conf-enabled/phpinfo.conf && \
echo 'LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\"" combined' > /etc/apache2/conf-enabled/logformat.conf && \
a2enmod rewrite && \
curl -o /usr/local/bin/phpunit -fL "https://phar.phpunit.de/phpunit-9.phar" && \
chmod +x /usr/local/bin/phpunit && \
ln -s html /var/www/src
#COPY php-mtt.ini /usr/local/etc/php/conf.d/
#COPY php-opcache.ini /usr/local/etc/php/conf.d/

View file

@ -1,17 +0,0 @@
services:
web:
build:
context: .
dockerfile: Dockerfile-web
image: mtt-dev/php:7.4-apache
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=sqlite
volumes:
- ../../../src:/var/www/html
- ../../../tests:/var/www/tests
- ./php-mtt.ini:/usr/local/etc/php/conf.d/php-mtt.ini
- ./php-opcache.ini:/usr/local/etc/php/conf.d/php-opcache.ini

View file

@ -1,9 +0,0 @@

; Since PHP 5.4 E_STRICT is included in E_ALL
error_reporting = E_ALL
log_errors = On
display_errors = On
display_startup_errors = On
session.gc_divisor = 100

View file

@ -1,34 +0,0 @@
;; opcache.ini
;; check /usr/local/etc/php/conf.d if exists docker-php-ext-opcache.ini
; To disable opcache just comment this line
zend_extension=opcache.so
[opcache]
opcache.enable=0
opcache.enable_cli=0
; The size of the shared memory storage used by OPcache, in megabytes. The minimum permissible value is "8", which is enforced if a smaller value is set.
; Default is 128.
opcache.memory_consumption=128
; The maximum number of keys (and therefore scripts) in the OPcache hash table.
; The actual value used will be the first number in the set of prime numbers
; { 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 }
; that is greater than or equal to the configured value.
; The minimum value is 200. The maximum value is 1000000. Values outside of this range are clamped to the permissible range.
; Default is 10000.
opcache.max_accelerated_files=1000
; How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.
; This configuration directive is ignored if opcache.validate_timestamps is disabled.
; Default is 2.
opcache.revalidate_freq=2
; If enabled, OPcache will check for updated scripts every opcache.revalidate_freq seconds.
; When this directive is disabled, you must reset OPcache manually via opcache_reset(), opcache_invalidate()
; or by restarting the Web server for changes to the filesystem to take effect.
; Default is 1.
;; Override in docker-compose
opcache.validate_timestamps=1

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php74-nginx

View file

@ -1,11 +0,0 @@
FROM php:7.4-fpm
RUN docker-php-ext-install mysqli && \
mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" && \
mkdir /var/www/phpinfo && \
echo "<?php\nphpinfo();" > /var/www/phpinfo/phpinfo.php
#COPY php-mtt.ini /usr/local/etc/php/conf.d/
#COPY php-opcache.ini /usr/local/etc/php/conf.d/
VOLUME /var/www/html

View file

@ -1,37 +0,0 @@
version: "3.9"
networks:
network:
name: "${PLATFORM_NAME}-network"
services:
web:
build:
context: ../_nginx
dockerfile: Dockerfile-nginx
image: mtt-dev/nginx
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
volumes:
- ../../../src:/var/www/html
depends_on:
- fpm
networks:
- network
fpm:
build:
context: .
dockerfile: Dockerfile-fpm
image: mtt-dev/php:7.4-fpm
container_name: ${PLATFORM_NAME}-fpm
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=sqlite
volumes:
- ../../../src:/var/www/html
- ./php-mtt.ini:/usr/local/etc/php/conf.d/php-mtt.ini
- ./php-opcache.ini:/usr/local/etc/php/conf.d/php-opcache.ini
networks:
- network

View file

@ -1,10 +0,0 @@

; Since PHP 5.4 E_STRICT is included in E_ALL
error_reporting = E_ALL
log_errors = On
display_errors = On
display_startup_errors = On
session.gc_divisor = 100
cgi.fix_pathinfo=0

View file

@ -1,42 +0,0 @@
;; opcache.ini
;; check /usr/local/etc/php/conf.d if exists docker-php-ext-opcache.ini
; To disable opcache just comment this line
zend_extension=opcache.so
[opcache]
opcache.enable=1
opcache.enable_cli=1
; JIT will work only if opcache is enabled and jit_buffer_size is not zero.
; To disable JIT set the buffer size to 0.
opcache.jit_buffer_size=64M
; JIT mode. Read more at https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.jit
; Default is tracing.
opcache.jit=tracing
; The size of the shared memory storage used by OPcache, in megabytes. The minimum permissible value is "8", which is enforced if a smaller value is set.
; Default is 128.
opcache.memory_consumption=128
; The maximum number of keys (and therefore scripts) in the OPcache hash table.
; The actual value used will be the first number in the set of prime numbers
; { 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 }
; that is greater than or equal to the configured value.
; The minimum value is 200. The maximum value is 1000000. Values outside of this range are clamped to the permissible range.
; Default is 10000.
opcache.max_accelerated_files=1000
; How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.
; This configuration directive is ignored if opcache.validate_timestamps is disabled.
; Default is 2.
opcache.revalidate_freq=2
; If enabled, OPcache will check for updated scripts every opcache.revalidate_freq seconds.
; When this directive is disabled, you must reset OPcache manually via opcache_reset(), opcache_invalidate()
; or by restarting the Web server for changes to the filesystem to take effect.
; Default is 1.
;; Override in docker-compose
opcache.validate_timestamps=1

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php80-apache-mariadb105

View file

@ -1,45 +0,0 @@
version: "3.9"
networks:
network:
name: "${PLATFORM_NAME}-network"
services:
web:
build:
context: ../mtt-php80-apache/
dockerfile: Dockerfile-web
image: mtt-dev/php:8.0-apache
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=mysql
- MTT_DB_HOST=db
- MTT_DB_NAME=mytinytodo
- MTT_DB_USER=mtt
- MTT_DB_PASSWORD=mtt
- MTT_DB_PREFIX=mtt_
- MTT_DB_DRIVER=mysqli
volumes:
- ../../../src:/var/www/html
depends_on:
- db
networks:
- network
db:
image: mariadb:10.5
container_name: ${PLATFORM_NAME}-db
#restart: always
environment:
MARIADB_ROOT_PASSWORD: JustForDev
MARIADB_USER: mtt
MARIADB_PASSWORD: mtt
MARIADB_DATABASE: mytinytodo
volumes:
- ../_mariadb105/my.cnf:/etc/mysql/conf.d/my.cnf
- ../_mariadb105/db_data:/var/lib/mysql
networks:
- network

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php80-apache

View file

@ -1,15 +0,0 @@
FROM php:8.0-apache
RUN docker-php-ext-install mysqli && \
mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" && \
mkdir /var/www/phpinfo && \
echo "<?php\nphpinfo();" > /var/www/phpinfo/phpinfo.php && \
echo 'Alias "/phpinfo" "/var/www/phpinfo/phpinfo.php"' > /etc/apache2/conf-enabled/phpinfo.conf && \
echo 'LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\"" combined' > /etc/apache2/conf-enabled/logformat.conf && \
a2enmod rewrite && \
curl -o /usr/local/bin/phpunit -fL "https://phar.phpunit.de/phpunit-9.phar" && \
chmod +x /usr/local/bin/phpunit && \
ln -s html /var/www/src
COPY php-mtt.ini /usr/local/etc/php/conf.d/
COPY php-opcache.ini /usr/local/etc/php/conf.d/

View file

@ -1,16 +0,0 @@
version: "3.9"
services:
web:
build:
context: .
dockerfile: Dockerfile-web
image: mtt-dev/php:8.0-apache
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=sqlite
volumes:
- ../../../src:/var/www/html

View file

@ -1,9 +0,0 @@

; Since PHP 5.4 E_STRICT is included in E_ALL
error_reporting = E_ALL
log_errors = On
display_errors = On
display_startup_errors = On
session.gc_divisor = 100

View file

@ -1,42 +0,0 @@
;; opcache.ini
;; check /usr/local/etc/php/conf.d if exists docker-php-ext-opcache.ini
; To disable opcache just comment this line
zend_extension=opcache.so
[opcache]
opcache.enable=0
opcache.enable_cli=0
; JIT will work only if opcache is enabled and jit_buffer_size is not zero.
; To disable JIT set the buffer size to 0.
opcache.jit_buffer_size=64M
; JIT mode. Read more at https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.jit
; Default is tracing.
opcache.jit=tracing
; The size of the shared memory storage used by OPcache, in megabytes. The minimum permissible value is "8", which is enforced if a smaller value is set.
; Default is 128.
opcache.memory_consumption=128
; The maximum number of keys (and therefore scripts) in the OPcache hash table.
; The actual value used will be the first number in the set of prime numbers
; { 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 }
; that is greater than or equal to the configured value.
; The minimum value is 200. The maximum value is 1000000. Values outside of this range are clamped to the permissible range.
; Default is 10000.
opcache.max_accelerated_files=1000
; How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.
; This configuration directive is ignored if opcache.validate_timestamps is disabled.
; Default is 2.
opcache.revalidate_freq=2
; If enabled, OPcache will check for updated scripts every opcache.revalidate_freq seconds.
; When this directive is disabled, you must reset OPcache manually via opcache_reset(), opcache_invalidate()
; or by restarting the Web server for changes to the filesystem to take effect.
; Default is 1.
;; Override in docker-compose
opcache.validate_timestamps=1

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php81-apache-mariadb108

View file

@ -1,56 +0,0 @@
version: "3.9"
networks:
network:
name: "${PLATFORM_NAME}-network"
services:
web:
build:
context: ../mtt-php81-apache/
dockerfile: Dockerfile-web
image: mtt-dev/php:8.1-apache
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=mysql
- MTT_DB_HOST=db
- MTT_DB_NAME=mytinytodo
- MTT_DB_USER=mtt
- MTT_DB_PASSWORD=mtt
- MTT_DB_PREFIX=mtt_
- MTT_DB_DRIVER=mysqli
volumes:
- ../../../src:/var/www/html
- ../../../tests:/var/www/tests
depends_on:
- db
networks:
- network
db:
image: mariadb:10.8
container_name: ${PLATFORM_NAME}-db
#restart: always
environment:
MARIADB_ROOT_PASSWORD: JustForDev
MARIADB_USER: mtt
MARIADB_PASSWORD: mtt
MARIADB_DATABASE: mytinytodo
volumes:
- ../_mariadb108/my.cnf:/etc/mysql/conf.d/my.cnf
- ../_mariadb108/db_data:/var/lib/mysql
networks:
- network
adminer:
image: adminer:latest
container_name: ${PLATFORM_NAME}-adminer
environment:
ADMINER_DEFAULT_SERVER: db
ports:
- 8079:8080
networks:
- network

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php81-apache

View file

@ -1,16 +0,0 @@
FROM php:8.1-apache
RUN docker-php-ext-install mysqli && \
mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" && \
mkdir /var/www/phpinfo && \
echo "<?php\nphpinfo();" > /var/www/phpinfo/phpinfo.php && \
echo 'Alias "/phpinfo" "/var/www/phpinfo/phpinfo.php"' > /etc/apache2/conf-enabled/phpinfo.conf && \
a2enmod rewrite && \
echo 'LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\"" combined' > /etc/apache2/conf-enabled/logformat.conf && \
curl -o /usr/local/bin/phpunit -fL "https://phar.phpunit.de/phpunit-9.phar" && \
chmod +x /usr/local/bin/phpunit && \
ln -s html /var/www/src
COPY php-mtt.ini /usr/local/etc/php/conf.d/
COPY php-opcache.ini /usr/local/etc/php/conf.d/

View file

@ -1,16 +0,0 @@
version: "3.9"
services:
web:
build:
context: .
dockerfile: Dockerfile-web
image: mtt-dev/php:8.1-apache
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=sqlite
volumes:
- ../../../src:/var/www/html

View file

@ -1,9 +0,0 @@

; Since PHP 5.4 E_STRICT is included in E_ALL
error_reporting = E_ALL
log_errors = On
display_errors = On
display_startup_errors = On
session.gc_divisor = 100

View file

@ -1,42 +0,0 @@
;; opcache.ini
;; check /usr/local/etc/php/conf.d if exists docker-php-ext-opcache.ini
; To disable opcache just comment this line
zend_extension=opcache.so
[opcache]
opcache.enable=0
opcache.enable_cli=0
; JIT will work only if opcache is enabled and jit_buffer_size is not zero.
; To disable JIT set the buffer size to 0.
opcache.jit_buffer_size=64M
; JIT mode. Read more at https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.jit
; Default is tracing.
opcache.jit=tracing
; The size of the shared memory storage used by OPcache, in megabytes. The minimum permissible value is "8", which is enforced if a smaller value is set.
; Default is 128.
opcache.memory_consumption=128
; The maximum number of keys (and therefore scripts) in the OPcache hash table.
; The actual value used will be the first number in the set of prime numbers
; { 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 }
; that is greater than or equal to the configured value.
; The minimum value is 200. The maximum value is 1000000. Values outside of this range are clamped to the permissible range.
; Default is 10000.
opcache.max_accelerated_files=1000
; How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.
; This configuration directive is ignored if opcache.validate_timestamps is disabled.
; Default is 2.
opcache.revalidate_freq=2
; If enabled, OPcache will check for updated scripts every opcache.revalidate_freq seconds.
; When this directive is disabled, you must reset OPcache manually via opcache_reset(), opcache_invalidate()
; or by restarting the Web server for changes to the filesystem to take effect.
; Default is 1.
;; Override in docker-compose
opcache.validate_timestamps=1

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php82-angie-postgres10

View file

@ -1,58 +0,0 @@
version: "3.9"
networks:
network:
name: "${PLATFORM_NAME}-network"
services:
web:
build:
context: ../_nginx
dockerfile: Dockerfile-angie-alpine
image: mtt-dev/angie:alpine
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
volumes:
- ../../../src:/var/www/html
depends_on:
- fpm
networks:
- network
fpm:
build:
context: ../mtt-php82-angie
dockerfile: Dockerfile-fpm
image: mtt-dev/php:8.2-fpm-alpine
container_name: ${PLATFORM_NAME}-fpm
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=postgres
- MTT_API_USE_PATH_INFO=YES
- MTT_DB_HOST=db
- MTT_DB_NAME=mtt
- MTT_DB_USER=mtt
- MTT_DB_PASSWORD=mtt
- MTT_DB_PREFIX=mtt_
volumes:
- ../../../src:/var/www/html
- ../../../tests:/var/www/tests
- ../mtt-php82-angie/php-mtt.ini:/usr/local/etc/php/conf.d/php-mtt.ini
- ../mtt-php82-angie/php-opcache.ini:/usr/local/etc/php/conf.d/php-opcache.ini
networks:
- network
db:
# do not use alpine image due to missing locales
image: postgres:10.0
container_name: ${PLATFORM_NAME}-db
userns_mode: keep-id
environment:
POSTGRES_PASSWORD: mtt
POSTGRES_USER: mtt
POSTGRES_DB: mtt
volumes:
- ../_postgres10/db_data:/var/lib/postgresql/data
networks:
- network

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php82-angie-alpine

View file

@ -1,17 +0,0 @@
FROM php:8.2-fpm-alpine
RUN apk add --update-cache libpq postgresql-dev icu icu-dev && \
docker-php-ext-install pdo_mysql pdo_pgsql intl && \
apk del postgresql-dev icu-dev && rm -rf /var/cache/apk/* && \
mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" && \
mkdir /var/www/phpinfo && \
echo "<?php phpinfo();" > /var/www/phpinfo/phpinfo.php && \
curl -o /usr/local/bin/phpunit -fL "https://phar.phpunit.de/phpunit-10.phar" && \
chmod +x /usr/local/bin/phpunit && \
ln -s html /var/www/src
COPY php-mtt.ini /usr/local/etc/php/conf.d/
COPY php-opcache.ini /usr/local/etc/php/conf.d/
COPY php-fpm-www.conf /usr/local/etc/php-fpm.d/www.conf
VOLUME /var/www/html

View file

@ -1,40 +0,0 @@
version: "3.9"
networks:
network:
name: "${PLATFORM_NAME}-network"
services:
web:
build:
context: ../_nginx
dockerfile: Dockerfile-angie-alpine
image: mtt-dev/angie:alpine
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
volumes:
- ../../../src:/var/www/html
depends_on:
- fpm
networks:
- network
fpm:
build:
context: .
dockerfile: Dockerfile-fpm
image: mtt-dev/php:8.2-fpm-alpine
container_name: ${PLATFORM_NAME}-fpm
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=sqlite
- MTT_API_USE_PATH_INFO=YES
volumes:
- ../../../src:/var/www/html
- ../../../tests:/var/www/tests
- ./php-mtt.ini:/usr/local/etc/php/conf.d/php-mtt.ini
- ./php-opcache.ini:/usr/local/etc/php/conf.d/php-opcache.ini
networks:
- network

View file

@ -1,13 +0,0 @@
[www]
user = www-data
group = www-data
listen = 127.0.0.1:9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 500
access.format = "%R - %u [%t] \"%m %r\" %s %f"
access.log = /dev/null

View file

@ -1,12 +0,0 @@

; Since PHP 5.4 E_STRICT is included in E_ALL
error_reporting = E_ALL
log_errors = On
display_errors = On
display_startup_errors = On
cgi.fix_pathinfo=0
session.gc_divisor = 100
allow_url_fopen=1

View file

@ -1,42 +0,0 @@
;; opcache.ini
;; check /usr/local/etc/php/conf.d if exists docker-php-ext-opcache.ini
; To disable opcache just comment this line
zend_extension=opcache.so
[opcache]
opcache.enable=1
opcache.enable_cli=1
; JIT will work only if opcache is enabled and jit_buffer_size is not zero.
; To disable JIT set the buffer size to 0.
opcache.jit_buffer_size=64M
; JIT mode. Read more at https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.jit
; Default is tracing.
opcache.jit=tracing
; The size of the shared memory storage used by OPcache, in megabytes. The minimum permissible value is "8", which is enforced if a smaller value is set.
; Default is 128.
opcache.memory_consumption=128
; The maximum number of keys (and therefore scripts) in the OPcache hash table.
; The actual value used will be the first number in the set of prime numbers
; { 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 }
; that is greater than or equal to the configured value.
; The minimum value is 200. The maximum value is 1000000. Values outside of this range are clamped to the permissible range.
; Default is 10000.
opcache.max_accelerated_files=1000
; How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.
; This configuration directive is ignored if opcache.validate_timestamps is disabled.
; Default is 2.
opcache.revalidate_freq=2
; If enabled, OPcache will check for updated scripts every opcache.revalidate_freq seconds.
; When this directive is disabled, you must reset OPcache manually via opcache_reset(), opcache_invalidate()
; or by restarting the Web server for changes to the filesystem to take effect.
; Default is 1.
;; Override in docker-compose
opcache.validate_timestamps=1

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php82-apache

View file

@ -1,17 +0,0 @@
FROM php:8.2-apache-buster
RUN apt-get update && apt-get install -y libicu-dev && \
docker-php-ext-install mysqli intl && \
apt-get -y autoremove && \
mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" && \
mkdir /var/www/phpinfo && \
a2enmod rewrite && \
echo "<?php\nphpinfo();" > /var/www/phpinfo/phpinfo.php && \
echo 'Alias "/phpinfo" "/var/www/phpinfo/phpinfo.php"' > /etc/apache2/conf-enabled/phpinfo.conf && \
echo 'LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\"" combined' > /etc/apache2/conf-enabled/logformat.conf && \
curl -o /usr/local/bin/phpunit -fL "https://phar.phpunit.de/phpunit-9.phar" && \
chmod +x /usr/local/bin/phpunit && \
ln -s html /var/www/src
COPY php-mtt.ini /usr/local/etc/php/conf.d/
COPY php-opcache.ini /usr/local/etc/php/conf.d/

View file

@ -1,19 +0,0 @@
version: "3.9"
services:
web:
build:
context: .
dockerfile: Dockerfile-web
image: mtt-dev/php:8.2-apache
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=sqlite
volumes:
- ../../../src:/var/www/html
- ../../../tests:/var/www/tests
- ./php-mtt.ini:/usr/local/etc/php/conf.d/php-mtt.ini
- ./php-opcache.ini:/usr/local/etc/php/conf.d/php-opcache.ini

View file

@ -1,9 +0,0 @@

; Since PHP 5.4 E_STRICT is included in E_ALL
error_reporting = E_ALL
log_errors = On
display_errors = On
display_startup_errors = On
session.gc_divisor = 100

View file

@ -1,42 +0,0 @@
;; opcache.ini
;; check /usr/local/etc/php/conf.d if exists docker-php-ext-opcache.ini
; To disable opcache just comment this line
zend_extension=opcache.so
[opcache]
opcache.enable=0
opcache.enable_cli=0
; JIT will work only if opcache is enabled and jit_buffer_size is not zero.
; To disable JIT set the buffer size to 0.
opcache.jit_buffer_size=64M
; JIT mode. Read more at https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.jit
; Default is tracing.
opcache.jit=tracing
; The size of the shared memory storage used by OPcache, in megabytes. The minimum permissible value is "8", which is enforced if a smaller value is set.
; Default is 128.
opcache.memory_consumption=128
; The maximum number of keys (and therefore scripts) in the OPcache hash table.
; The actual value used will be the first number in the set of prime numbers
; { 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 }
; that is greater than or equal to the configured value.
; The minimum value is 200. The maximum value is 1000000. Values outside of this range are clamped to the permissible range.
; Default is 10000.
opcache.max_accelerated_files=1000
; How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.
; This configuration directive is ignored if opcache.validate_timestamps is disabled.
; Default is 2.
opcache.revalidate_freq=2
; If enabled, OPcache will check for updated scripts every opcache.revalidate_freq seconds.
; When this directive is disabled, you must reset OPcache manually via opcache_reset(), opcache_invalidate()
; or by restarting the Web server for changes to the filesystem to take effect.
; Default is 1.
;; Override in docker-compose
opcache.validate_timestamps=1

View file

@ -1 +0,0 @@
PLATFORM_NAME=mtt-dev-php83-apache

View file

@ -1,15 +0,0 @@
FROM php:8.3-rc-apache
RUN docker-php-ext-install mysqli && \
mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" && \
mkdir /var/www/phpinfo && \
a2enmod rewrite && \
echo "<?php\nphpinfo();" > /var/www/phpinfo/phpinfo.php && \
echo 'Alias "/phpinfo" "/var/www/phpinfo/phpinfo.php"' > /etc/apache2/conf-enabled/phpinfo.conf && \
echo 'LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\"" combined' > /etc/apache2/conf-enabled/logformat.conf && \
curl -o /usr/local/bin/phpunit -fL "https://phar.phpunit.de/phpunit-9.phar" && \
chmod +x /usr/local/bin/phpunit && \
ln -s html /var/www/src
COPY php-mtt.ini /usr/local/etc/php/conf.d/
COPY php-opcache.ini /usr/local/etc/php/conf.d/

View file

@ -1,19 +0,0 @@
version: "3.9"
services:
web:
build:
context: .
dockerfile: Dockerfile-web
image: mtt-dev/php:8.3-apache
container_name: ${PLATFORM_NAME}-web
ports:
- "8080:80"
environment:
- MTT_ENABLE_DEBUG=YES
- MTT_DB_TYPE=sqlite
volumes:
- ../../../src:/var/www/html
- ../../../tests:/var/www/tests
- ./php-mtt.ini:/usr/local/etc/php/conf.d/php-mtt.ini
- ./php-opcache.ini:/usr/local/etc/php/conf.d/php-opcache.ini

View file

@ -1,11 +0,0 @@

; Since PHP 5.4 E_STRICT is included in E_ALL
error_reporting = E_ALL
log_errors = On
display_errors = On
display_startup_errors = On
session.gc_divisor = 100
allow_url_fopen=1

View file

@ -1,42 +0,0 @@
;; opcache.ini
;; check /usr/local/etc/php/conf.d if exists docker-php-ext-opcache.ini
; To disable opcache just comment this line
zend_extension=opcache.so
[opcache]
opcache.enable=0
opcache.enable_cli=0
; JIT will work only if opcache is enabled and jit_buffer_size is not zero.
; To disable JIT set the buffer size to 0.
opcache.jit_buffer_size=64M
; JIT mode. Read more at https://www.php.net/manual/en/opcache.configuration.php#ini.opcache.jit
; Default is tracing.
opcache.jit=tracing
; The size of the shared memory storage used by OPcache, in megabytes. The minimum permissible value is "8", which is enforced if a smaller value is set.
; Default is 128.
opcache.memory_consumption=128
; The maximum number of keys (and therefore scripts) in the OPcache hash table.
; The actual value used will be the first number in the set of prime numbers
; { 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793 }
; that is greater than or equal to the configured value.
; The minimum value is 200. The maximum value is 1000000. Values outside of this range are clamped to the permissible range.
; Default is 10000.
opcache.max_accelerated_files=1000
; How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.
; This configuration directive is ignored if opcache.validate_timestamps is disabled.
; Default is 2.
opcache.revalidate_freq=2
; If enabled, OPcache will check for updated scripts every opcache.revalidate_freq seconds.
; When this directive is disabled, you must reset OPcache manually via opcache_reset(), opcache_invalidate()
; or by restarting the Web server for changes to the filesystem to take effect.
; Default is 1.
;; Override in docker-compose
opcache.validate_timestamps=1

View file

@ -1,8 +0,0 @@
Docker containers for development and testing purposes.
Not recommended for production usage!
To run docker container:
cd mtt-php74-apache
docker-compose build --pull
docker-compose up

View file

@ -1,12 +1,29 @@
# For Apache
# For REST API in Apache
#<IfModule mod_rewrite.c>
# RewriteEngine On
# RewriteCond %{REQUEST_FILENAME} !-f
# RewriteCond %{REQUEST_FILENAME} !-d
# RewriteRule ^api/(.*)$ api.php/$1 [L,QSA]
#</IfModule>
#<Limit GET POST PUT DELETE>
# Allow from all
#</Limit>
# For Nginx set something like this:
# In Nginx set something like this:
# Deny access to some files and folders
#location ~ ^/(db|includes)/ {
# deny all;
#}
#location ~ /\.ht {
# deny all;
#}
#location ~* ^/ext/.*\.(json|md)$ {
# deny all;
#}
# Optional
# location /api/ {
# rewrite ^/api/(.*) /api.php/$1 last;
# }

View file

@ -16,7 +16,7 @@ https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
myTinyTodo
--------------
Url: https://www.mytinytodo.net/
Copyright: 2009-2011,2019-2023 Max Pozdeev <maxpozdeev@gmail.com>
Copyright: 2009-2011,2019-2025 Max Pozdeev <maxpozdeev@gmail.com>
License: GPL version 2 or any later (see LICENSE file)
@ -48,7 +48,12 @@ Url: https://parsedown.org/
Copyright: (c) 2013-2018 Emanuil Rusev, erusev.com
License: MIT license. Compatible with GNU GPL.
Other libraries (in includes/vendor)
----------------------------------------------
symfony/polyfill-intl-normalizer
league/commonmark
Images
------
--------------
This software contains images by 3d-parties.
See files content/themes/images/COPYRIGHT for details.
See file content/theme/images/COPYRIGHT for details.

View file

@ -32,6 +32,7 @@ $endpoints = array(
'GET' => [ ListsController::class , 'getId' ],
'PUT' => [ ListsController::class , 'putId' ],
'DELETE' => [ ListsController::class , 'deleteId' ],
'POST' => [ ListsController::class , 'putId' ], //compatibility
],
'/tasks' => [
'GET' => [ TasksController::class , 'get' ],
@ -41,6 +42,7 @@ $endpoints = array(
'/tasks/(-?\d+)' => [
'PUT' => [ TasksController::class , 'putId' ],
'DELETE' => [ TasksController::class , 'deleteId' ],
'POST' => [ TasksController::class , 'putId' ], //compatibility
],
'/tasks/parseTitle' => [
'POST' => [ TasksController::class , 'postTitleParse' ],
@ -60,6 +62,7 @@ $endpoints = array(
'/ext-settings/(.+)' => [
'GET' => [ ExtSettingsController::class , 'get' ],
'PUT' => [ ExtSettingsController::class , 'put' ],
'POST' => [ ExtSettingsController::class , 'put' ], //compatibility
]
);
@ -148,7 +151,7 @@ function myErrorHandler($errno, $errstr, $errfile, $errline)
if ($errno==E_ERROR || $errno==E_CORE_ERROR || $errno==E_COMPILE_ERROR || $errno==E_USER_ERROR || $errno==E_PARSE) {
$error = 'Error';
}
elseif ($errno==E_WARNING || $errno==E_CORE_WARNING || $errno==E_COMPILE_WARNING || $errno==E_USER_WARNING || $errno==E_STRICT) {
elseif ($errno==E_WARNING || $errno==E_CORE_WARNING || $errno==E_COMPILE_WARNING || $errno==E_USER_WARNING) {
if (error_reporting() & $errno) $error = 'Warning'; else return;
}
elseif ($errno==E_NOTICE || $errno==E_USER_NOTICE || $errno==E_DEPRECATED || $errno==E_USER_DEPRECATED) {
@ -197,6 +200,7 @@ function checkReadAccess(?int $listId = null)
$id = $db->sq("SELECT id FROM {$db->prefix}lists WHERE id=? AND published=1", array($listId));
if ($id) return;
}
http_response_code(403);
jsonExit( array('total'=>0, 'list'=>array(), 'denied'=>1) );
}

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
/*!
* jQuery UI Touch Punch 1.0.8 as modified by RWAP Software
* jQuery UI Touch Punch 1.1.5 as modified by RWAP Software
* based on original touchpunch v0.2.3 which has not been updated since 2014
*
* Updates by RWAP Software to take account of various suggested changes on the original code issues
@ -22,7 +22,7 @@
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
define([ "jquery", "jquery.ui" ], factory );
define([ "jquery", "jquery-ui" ], factory );
} else {
// Browser globals
@ -31,31 +31,30 @@
}(function ($) {
// Detect touch support - Windows Surface devices and other touch devices
$.support.mspointer = window.navigator.msPointerEnabled;
$.support.touch = ( 'ontouchstart' in document
|| 'ontouchstart' in window
|| window.TouchEvent
|| (window.DocumentTouch && document instanceof DocumentTouch)
|| navigator.maxTouchPoints > 0
|| navigator.msMaxTouchPoints > 0
$.mspointer = window.navigator.msPointerEnabled;
$.touch = ( 'ontouchstart' in document
|| 'ontouchstart' in window
|| window.TouchEvent
|| (window.DocumentTouch && document instanceof DocumentTouch)
|| navigator.maxTouchPoints > 0
|| navigator.msMaxTouchPoints > 0
);
// Ignore browsers without touch or mouse support
if ((!$.support.touch && !$.support.mspointer) || !$.ui.mouse) {
return;
if ((!$.touch && !$.mspointer) || !$.ui.mouse) {
return;
}
var mouseProto = $.ui.mouse.prototype,
let mouseProto = $.ui.mouse.prototype,
_mouseInit = mouseProto._mouseInit,
_mouseDestroy = mouseProto._mouseDestroy,
touchHandled;
touchHandled, lastClickTime = 0;
var delay = 300,
let delay = 300,
delayTimer,
delayEvent,
delayStarted = false,
delayFinished = false,
lastClickTimeStamp = 0,
lastClickCoord;
@ -82,32 +81,26 @@
return;
}
//Ignore input or textarea elements so user can still enter text
if ($(event.target).is("input") || $(event.target).is("textarea")) {
return;
}
// Prevent "Ignored attempt to cancel a touchmove event with cancelable=false" errors
if (event.cancelable) {
event.preventDefault();
}
var touch = event.originalEvent.changedTouches[0],
simulatedEvent = document.createEvent('MouseEvents');
// Initialize the simulated mouse event using the touch event's coordinates
simulatedEvent.initMouseEvent(
simulatedType, // type
true, // bubbles
true, // cancelable
window, // view
1, // detail
touch.screenX, // screenX
touch.screenY, // screenY
touch.clientX, // clientX
touch.clientY, // clientY
false, // ctrlKey
false, // altKey
false, // shiftKey
false, // metaKey
0, // button
null // relatedTarget
);
let touch = event.originalEvent.changedTouches[0],
simulatedEvent = new MouseEvent(simulatedType, {
bubbles: true,
cancelable: true,
view:window,
screenX:touch.screenX,
screenY:touch.screenY,
clientX:touch.clientX,
clientY:touch.clientY
});
// Dispatch the simulated event to the target element
event.target.dispatchEvent(simulatedEvent);
@ -125,7 +118,7 @@
function fireMouseDown () {
var self = this;
const self = this;
delayFinished = true;
@ -152,7 +145,7 @@
*/
mouseProto._touchStart = function (event) {
var self = this;
let self = this;
// Interaction time
this._startedMove = event.timeStamp;
@ -224,22 +217,23 @@
// If the touch interaction did not move, it should trigger a click
// Check for this in two ways - length of time of simulation and distance moved
// Allow for Apple Stylus to be used also
var timeMoving = event.timeStamp - this._startedMove;
let timeMoving = event.timeStamp - this._startedMove;
if (!this._touchMoved || timeMoving < 500) {
// Simulate the click event
simulateMouseEvent(event, 'click');
if (lastClickTimeStamp != 0 && event.timeStamp - lastClickTimeStamp < 500 &&
// Simulate the dblclick event if last click was not far away from the previous one
if ( event.timeStamp - lastClickTime < 400 &&
Math.abs(lastClickCoord.x - this._startPos.x) < 10 && Math.abs(lastClickCoord.y - this._startPos.y) < 10) {
// Simulate the dblclick event
simulateMouseEvent(event, 'dblclick');
}
lastClickTimeStamp = event.timeStamp
// Simulate the click event
else
simulateMouseEvent(event, 'click');
lastClickTime = event.timeStamp
lastClickCoord = this._startPos;
}
else {
var endPos = getTouchCoords(event);
let endPos = getTouchCoords(event);
if ((Math.abs(endPos.x - this._startPos.x) < 10) && (Math.abs(endPos.y - this._startPos.y) < 10)) {
// If the touch interaction did not move, it should trigger a click
if (!this._touchMoved || event.originalEvent.changedTouches[0].touchType === 'stylus') {
@ -256,6 +250,10 @@
touchHandled = false;
};
let _touchStartBound;
let _touchMoveBound;
let _touchEndBound
/**
* A duck punch of the $.ui.mouse _mouseInit method to support touch events.
* This method extends the widget with bound touch event handlers that
@ -264,18 +262,22 @@
*/
mouseProto._mouseInit = function () {
var self = this;
let self = this;
// Microsoft Surface Support = remove original touch Action
if ($.support.mspointer) {
if ($.mspointer) {
self.element[0].style.msTouchAction = 'none';
}
}
_touchStartBound = mouseProto._touchStart.bind(self);
_touchMoveBound = mouseProto._touchMove.bind(self);
_touchEndBound = mouseProto._touchEnd.bind(self);
// Delegate the touch handlers to the widget's element
self.element.on({
touchstart: $.proxy(self, '_touchStart'),
touchmove: $.proxy(self, '_touchMove'),
touchend: $.proxy(self, '_touchEnd')
touchstart: _touchStartBound,
touchmove: _touchMoveBound,
touchend: _touchEndBound
});
// Call the original $.ui.mouse init method
@ -287,13 +289,13 @@
*/
mouseProto._mouseDestroy = function () {
var self = this;
let self = this;
// Delegate the touch handlers to the widget's element
self.element.off({
touchstart: $.proxy(self, '_touchStart'),
touchmove: $.proxy(self, '_touchMove'),
touchend: $.proxy(self, '_touchEnd')
touchstart: _touchStartBound,
touchmove: _touchMoveBound,
touchend: _touchEndBound
});
// Call the original $.ui.mouse destroy method

View file

@ -1,6 +1,6 @@
/*
This file is a part of myTinyTodo.
(C) Copyright 2009-2010,2020-2023 Max Pozdeev <maxpozdeev@gmail.com>
(C) Copyright 2009-2010,2020-2025 Max Pozdeev <maxpozdeev@gmail.com>
Licensed under the GNU GPL version 2 or any later. See file COPYRIGHT for details.
*/
@ -66,7 +66,7 @@ var mytinytodo = window.mytinytodo = _mtt = {
openList: 0,
autotag: false,
instantSearch: true,
tagPreview: true,
tagPreview: false,
tagPreviewDelay: 700, //milliseconds
ajaxAnimationDelay: 200,
saveShowNotes: false,
@ -78,13 +78,15 @@ var mytinytodo = window.mytinytodo = _mtt = {
history: true,
markdown: true,
viewTaskOnClick: false,
newTaskCounter: true,
newTaskCounter: false,
newTaskCounterIcon: false,
},
timers: {
previewtag: 0,
ajaxAnimation: 0,
newTaskCounter: 0,
searchTags: 0,
},
lang: {
@ -136,7 +138,9 @@ var mytinytodo = window.mytinytodo = _mtt = {
// procs
setApiDriver: function(driver)
{
this.db = new driver(_mtt);
this.db = new driver({
useREST: false
});
return this;
},
@ -289,19 +293,42 @@ var mytinytodo = window.mytinytodo = _mtt = {
else {
$('#tagcloudAllLists').prop('checked', flag.showTagsFromAllLists).prop('disabled', false);
}
if(!_mtt.menus.tagcloud) _mtt.menus.tagcloud = new mttMenu('tagcloud', {
if (!_mtt.menus.tagcloud) _mtt.menus.tagcloud = new mttMenu('tagcloud', {
beforeShow: function(){
if(flag.tagsChanged) {
if (flag.tagsChanged) {
$('#tagcloudcontent').html('');
$('#tagcloudload').show();
loadTags(curList.id, function(){$('#tagcloudload').hide();});
loadTags(curList.id, function() {
$('#tagcloudload').hide();
document.getElementById('tagcloudSearch').value = '';
});
}
},
alignRight:true
alignRight: true,
onClose: function(){
document.getElementById('tagcloudSearch').value = '';
searchTags();
}
});
_mtt.menus.tagcloud.show(this);
});
$('#tagcloudSearch').keyup(function(event) {
if (event.keyCode == 27) return;
clearTimeout(_mtt.timers.searchTags);
_mtt.timers.searchTags = setTimeout(function(){searchTags()}, 400);
})
.keydown(function(event){
if (event.keyCode == 27) { // Cancel on Esc
if (this.value === '') return; //allow to close the popup
this.value = '';
clearTimeout(_mtt.timers.searchTags);
searchTags();
return false;
}
})
$('#tagcloudcancel').click(function(){
if(_mtt.menus.tagcloud) _mtt.menus.tagcloud.close();
});
@ -309,7 +336,8 @@ var mytinytodo = window.mytinytodo = _mtt = {
$('#tagcloudcontent').on('click', '.tag', function(event){
//tag is not escaped
addFilterTag( this.dataset.tag, this.dataset.tagId, (event.metaKey || event.ctrlKey ? true : false) );
if(_mtt.menus.tagcloud) _mtt.menus.tagcloud.close();
if (_mtt.menus.tagcloud)
_mtt.menus.tagcloud.close();
return false;
});
@ -317,7 +345,10 @@ var mytinytodo = window.mytinytodo = _mtt = {
flag.showTagsFromAllLists = this.checked;
$('#tagcloudcontent').html('');
$('#tagcloudload').show();
loadTags(curList.id, function(){$('#tagcloudload').hide();});
loadTags(curList.id, function(){
$('#tagcloudload').hide();
$('#tagcloudSearch').val('');
});
});
$('#mtt-notes-show').click(function(e){
@ -412,6 +443,8 @@ var mytinytodo = window.mytinytodo = _mtt = {
dayNames:_mtt.lang.daysLong,
monthNamesShort:_mtt.lang.monthsShort,
monthNames:_mtt.lang.monthsLong,
changeMonth: true,
changeYear: true,
isRTL: _mtt.lang.isRTL()
});
@ -716,11 +749,15 @@ var mytinytodo = window.mytinytodo = _mtt = {
window.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) {
document.documentElement.setAttribute('data-system-appearance', e.matches ? 'dark' : 'light');
});
}
}
// Counter
if (this.options.newTaskCounter) {
if (this.options.newTaskCounter /* TODO: && !flag.readOnly */) {
this.addAction('listsLoaded', newTaskCounterStart);
this.addAction('listSelected', newTaskCounterOnListSelected)
if (this.options.newTaskCounterIcon) {
this.addAction('newTaskCounterUpdated', newTaskCounterUpdated);
}
}
this.doAction( 'init' );
@ -865,16 +902,19 @@ var mytinytodo = window.mytinytodo = _mtt = {
duedatepickerformat: function()
{
if(!this.options.duedatepickerformat) return 'yy-mm-dd';
if (!this.options.duedatepickerformat)
return 'yy-mm-dd';
var s = this.options.duedatepickerformat.replace(/(.)/g, function(t,s) {
const s = this.options.duedatepickerformat.replace(/(.)/g, function(t,s) {
switch(t) {
case 'Y': return 'yy';
case 'y': return 'yy';
case 'd': return 'dd';
case 'j': return 'd';
case 'm': return 'mm';
case 'M': return 'M';
case 'n': return 'm';
case ' ':
case '/':
case '.':
case '-': return t;
@ -882,7 +922,8 @@ var mytinytodo = window.mytinytodo = _mtt = {
}
});
if(s == '') return 'yy-mm-dd';
if (s == '')
return 'yy-mm-dd';
return s;
},
@ -939,25 +980,38 @@ var mytinytodo = window.mytinytodo = _mtt = {
filter: {
_filters: [],
clear: function() {
clear() {
this._filters = [];
$('#mtt-tag-toolbar').hide();
$('#mtt-tag-filters').html('');
},
addTag: function(tagId, tag, exclude)
addTag(tagId, tag, exclude)
{
tagId += 0;
for (let i in this._filters) {
if (this._filters[i].tagId && this._filters[i].tagId == tagId)
//Catch 'any tag' filter
if (tagId == -2) {
tagId = -1;
tag = '^';
exclude = true
}
for (const filter of this._filters) {
if (filter.tagId && filter.tagId == tagId)
return false;
}
this._filters.push({tagId:tagId, tag:tag, exclude:exclude});
if (tagId == -1) {
// for display purposes only
tag = exclude ? _mtt.lang.get('withAnyTag') : _mtt.lang.get('withoutTags');
exclude = false;
}
const tagHtml = this.prepareTagHtml(tagId, tag, ['tag-filter', 'tag-id-'+tagId, exclude ? 'tag-filter-exclude' : '']) ;
$('#mtt-tag-filters').append(tagHtml);
$('#mtt-tag-toolbar').show();
return true;
},
cancelTag: function(tagId)
cancelTag(tagId)
{
for (let i in this._filters) {
if (this._filters[i].tagId && this._filters[i].tagId == tagId) {
@ -971,23 +1025,25 @@ var mytinytodo = window.mytinytodo = _mtt = {
}
return false;
},
getTags: function(withExcluded)
getTags(withExcluded)
{
let a = [];
for (let i in this._filters) {
if (this._filters[i].tagId) {
if (this._filters[i].exclude && withExcluded)
a.push('^'+ this._filters[i].tag);
else if (!this._filters[i].exclude)
a.push(this._filters[i].tag)
for (const filter of this._filters) {
if (filter.tagId) {
if (filter.exclude && withExcluded)
a.push('^'+ filter.tag);
else if (!filter.exclude)
a.push(filter.tag)
}
}
return a.join(', ');
},
prepareTagHtml: function(tagId, tag, classes)
prepareTagHtml(tagId, tag, classes)
{
// tag is not escaped
return '<span class="' + classes.join(' ') + ' mtt-filter-close" tagid="' + tagId + '">' + escapeHtml(tag) + '<span class="tag-filter-btn"></span></span>';
return `<span class="${classes.join(' ')} mtt-filter-close" tagid="${tagId}">${escapeHtml(tag)}<span class="tag-filter-btn"></span></span>`;
}
},
@ -1177,7 +1233,8 @@ function loadTasks(opts)
changeTaskCnt(item, 1);
});
curList.lastTime = json.time;
$('#list_'+curList.id).find('.counter').text('').addClass('hidden');
setNewTaskCounterForList(curList.id, 0);
_mtt.doAction("newTaskCounterUpdated", curList.id);
if(opts.beforeShow && opts.beforeShow.call) {
opts.beforeShow();
}
@ -1224,9 +1281,9 @@ function prepareTaskBlocks(item)
'<div class="task-through">' +
preparePrio(item.prio,id) +
'<span class="task-title">' + prepareTaskTitleInlineHtml(item.title) + '</span> ' +
(curList.id == -1 ? '<span class="task-listname">'+ tabLists.get(item.listId).name +'</span>' : '') +
(curList.id == -1 ? prepareListNameInline(item) : '') +
'<span class="task-tags">' + prepareTagsStr(item) + '</span>' +
'<span class="task-date">' + prepareInlineDate(item) + '</span>' +
'<div class="task-date">' + prepareInlineDate(item) + '</div>' +
'</div>' +
'<div class="task-through-right">' + prepareDueDate(item) + "</div>" +
'</div>' +
@ -1247,14 +1304,22 @@ _mtt.prepareTaskBlocks = prepareTaskBlocks;
function prepareTaskTitleInlineHtml(s)
{
// Task title is already escaped on php back-end
// Task title is already escaped on back-end
return s;
}
_mtt.prepareTaskTitleInlineHtml = prepareTaskTitleInlineHtml;
function prepareListNameInline(item)
{
// Used in AllTasks list
// List name is already escaped on back-end
return '<span class="task-listname">'+ item.listName +'</span>';
}
_mtt.prepareListNameInline = prepareListNameInline;
function prepareTaskNoteInlineHtml(s, rawText)
{
// Task note is already escaped on php back-end
// Task note is already escaped on back-end
return s;
};
_mtt.prepareTaskNoteInlineHtml = prepareTaskNoteInlineHtml;
@ -1359,9 +1424,9 @@ function changeTaskOrder(id)
return 0;
}
// sortByHand
if (curList.sort == 0) {
if (curList.sort == 0 || curList.sort == 100) {
taskOrder.sort( (a, b) => firstNonZero(
0,
curList.sort,
taskList[a].compl - taskList[b].compl,
taskList[a].ow - taskList[b].ow
))
@ -1468,13 +1533,13 @@ function setTaskPrio(id, prio)
taskList[id].prio = prio;
var $t = $('#taskrow_'+id);
$t.find('.task-prio').replaceWith(preparePrio(prio, id));
if(curList.sort != 0) changeTaskOrder(id);
if (curList.sort != 0 && curList.sort != 100) changeTaskOrder(id);
$t.effect("highlight", {color:_mtt.theme.editTaskFlashColor}, 'normal');
};
function setSort(v, init)
{
if (v < 0 || (v > 5 && v < 101) || v > 105) {
if (v < 0 || (v > 5 && v < 100) || v > 105) {
return;
}
curList.sort = v;
@ -1485,7 +1550,7 @@ function setSort(v, init)
function updateSortUI(v)
{
$('#listmenucontainer .sort-item').removeClass('mtt-item-checked').children('.mtt-sort-direction').text('');
if (v == 0) $('#sortByHand').addClass('mtt-item-checked');
if (v == 0 || v == 100) $('#sortByHand').addClass('mtt-item-checked').children('.mtt-sort-direction').text(v==0 ? '↓' : '↑');
else if(v==1 || v==101) $('#sortByPrio').addClass('mtt-item-checked').children('.mtt-sort-direction').text(v==1 ? '↑' : '↓');
else if(v==2 || v==102) $('#sortByDueDate').addClass('mtt-item-checked').children('.mtt-sort-direction').text(v==2 ? '↑' : '↓');
else if(v==3 || v==103) $('#sortByDateCreated').addClass('mtt-item-checked').children('.mtt-sort-direction').text(v==3 ? '↓' : '↑');
@ -1494,7 +1559,7 @@ function updateSortUI(v)
else return;
curList.sort = v;
if (v == 0 && !flag.readOnly) $("#tasklist").sortable('enable');
if ( (v == 0 || v == 100) && !flag.readOnly) $("#tasklist").sortable('enable');
else $("#tasklist").sortable('disable');
};
@ -1611,9 +1676,12 @@ function tabSelect(elementOrId)
if (id == -1) $('#mtt').addClass('show-all-tasks');
else $('#mtt').removeClass('show-all-tasks');
if (filter.search != '') liveSearchToggle(0, 1);
mytinytodo.doAction('listSelected', tabLists.get(id));
mytinytodo.doAction('listSelected', {
'list': curList,
'prevList':prevList
});
}
const newTitle = curList.name + ' - ' + _mtt.options.title;
const newTitle = dehtml(curList.name) + ' - ' + _mtt.options.title;
const isFirstLoad = flag.firstLoad;
//replaceHistoryState( 'list', { list:id }, _mtt.urlForList(curList), newTitle );
updateHistoryState( { list:id }, _mtt.urlForList(curList), newTitle );
@ -1664,7 +1732,7 @@ function listMenuClick(el, menu)
case 'btnRssFeed': return true;
case 'btnShowCompleted': showCompletedToggle(); break;
case 'btnClearCompleted': clearCompleted(); break;
case 'sortByHand': setSort(0); break;
case 'sortByHand': setSort(curList.sort==0 ? 100 : 0); break;
case 'sortByPrio': setSort(curList.sort==1 ? 101 : 1); break;
case 'sortByDueDate': setSort(curList.sort==2 ? 102 : 2); break;
case 'sortByDateCreated': setSort(curList.sort==3 ? 103 : 3); break;
@ -1781,7 +1849,7 @@ function fillTaskViewer(id)
$('#page_taskviewer .prio .content').html(preparePrio(item.prio,item.id));
$('#page_taskviewer .due .content').html(item.duedate);
$('#page_taskviewer .tags .content').html(prepareTagsStr(item, ''));
$('#page_taskviewer .list .content').text(curList.name);
$('#page_taskviewer .list .content').text(curList.id == -1 ? item.listName : curList.name);
if (item.note == '') {
$('#page_taskviewer').addClass('no-note');
}
@ -1796,7 +1864,7 @@ function viewTask(id)
const item = fillTaskViewer(id);
if (!item) return;
_mtt.pageSet('taskviewer');
updateHistoryState({ task: item.id, list: item.listId }, '#task/'+item.id, dehtml(item.title) + ' - ' + curList.name + ' - ' + _mtt.options.title);
updateHistoryState({ task: item.id, list: item.listId }, '#task/'+item.id, dehtml(item.title) + ' - ' + dehtml(curList.name) + ' - ' + _mtt.options.title);
}
@ -1899,8 +1967,9 @@ function saveTask(form)
taskList[item.id] = item;
const noteExpanded = (item.note != '' && $('#taskrow_'+item.id).is('.task-expanded')) ? 1 : 0;
$('#taskrow_'+item.id).replaceWith(_mtt.prepareTaskStr(item, noteExpanded));
if (curList.sort != 0)
if (curList.sort != 0 && curList.sort != 100) {
changeTaskOrder(item.id);
}
refreshTaskCnt();
_mtt.pageBack(); //back to list or viewer
if (_mtt.pages.current.page == 'taskviewer') {
@ -1963,20 +2032,29 @@ function loadTags(listId, callback)
_mtt.db.request('tagCloud', {list:listId}, function(json){
if (!parseInt(json.total)) tagsList = [];
else tagsList = json.items;
let cloud = '';
tagsList.forEach( item => {
// item.tag is escaped with htmlspecialchars()
cloud += ' <span class="tag" data-tag="' + item.tag + '" data-tag-id="' + item.id + '">' + item.tag + '</span>';
});
if (cloud == '') {
cloud = _mtt.lang.get('noTags');
}
$('#tagcloudcontent').html(cloud)
flag.tagsChanged = false;
setTagcloudContent(tagsList);
callback();
});
};
function setTagcloudContent(tags, isFiltered = false)
{
let cloud = '';
tags.forEach( item => {
// item.tag is escaped with htmlspecialchars()
cloud += ` <span class="tag" data-tag="${item.tag}" data-tag-id="${item.id}">${item.tag}</span>`;
});
if (cloud == '') {
cloud = _mtt.lang.get('noTags');
}
else if (!isFiltered) {
cloud = `<span class="tag special-no-tags" data-tag="^" data-tag-id="-1">${_mtt.lang.get('withoutTags')}</span>` +
`<span class="tag special-any-tag" data-tag="^^" data-tag-id="-2">${_mtt.lang.get('withAnyTag')}</span>` + cloud;
}
$('#tagcloudcontent').html(cloud)
}
function cancelTagFilter(tagId, dontLoadTasks)
{
if(tagId) _mtt.filter.cancelTag(tagId);
@ -1986,10 +2064,27 @@ function cancelTagFilter(tagId, dontLoadTasks)
function addFilterTag(tag, tagId, exclude)
{
if(!_mtt.filter.addTag(tagId, tag, exclude)) return false;
if (!_mtt.filter.addTag(tagId, tag, exclude))
return false;
loadTasks();
};
function searchTags()
{
const filter = document.getElementById('tagcloudSearch').value.toLocaleLowerCase();
if (filter === '') {
setTagcloudContent(tagsList);
return;
}
const filtered = [];
tagsList.forEach( item => {
if (item.tagText.toLocaleLowerCase().search(filter) === -1)
return;
filtered.push(item);
});
setTagcloudContent(filtered, true);
}
function liveSearchToggle(toSearch, dontLoad)
{
if(toSearch)
@ -2046,6 +2141,7 @@ function submitFullTask(form)
var item = json.list[0];
taskList[item.id] = item;
taskOrder.push(parseInt(item.id));
curList.lastTaskCreatedTime = item.dateInt;
$('#tasklist').append(_mtt.prepareTaskStr(item));
changeTaskOrder(item.id);
_mtt.pageBack();
@ -2068,39 +2164,50 @@ function tasklistSortStart(event, ui)
function tasklistSortUpdated(event, ui)
{
if(!ui.item[0]) return;
var itemId = ui.item[0].id;
var n = $(this).sortable('toArray');
if (!ui.item[0]) {
return;
}
const itemId = ui.item[0].id;
const n = $(this).sortable('toArray');
// remove possible empty id's
for(var i=0; i<sortOrder.length; i++) {
if(sortOrder[i] == '') { sortOrder.splice(i,1); i--; }
for (let i = 0; i < sortOrder.length; i++) {
if (sortOrder[i] == '') {
sortOrder.splice(i,1); i--;
}
}
if (n.toString() == sortOrder.toString()) {
return;
}
if(n.toString() == sortOrder.toString()) return;
// make index: id=>position
var h0 = {}; //before
for(var j=0; j<sortOrder.length; j++) {
h0[sortOrder[j]] = j;
const posBefore = {};
for (let j = 0; j < sortOrder.length; j++) {
posBefore[sortOrder[j]] = j;
}
var h1 = {}; //after
for(var j=0; j<n.length; j++) {
h1[n[j]] = j;
const posAfter = {};
for (let j = 0; j < n.length; j++) {
posAfter[n[j]] = j;
taskOrder[j] = parseInt(n[j].split('_')[1]);
}
// prepare param
var o = [];
var diff;
var replaceOW = taskList[sortOrder[h1[itemId]].split('_')[1]].ow;
for(var j in h0)
// prepare params
const o = [];
const newWeight = taskList[sortOrder[posAfter[itemId]].split('_')[1]].ow;
let diff;
for (const j in posBefore)
{
diff = h1[j] - h0[j];
if(diff != 0) {
var a = j.split('_');
if(j == itemId) diff = replaceOW - taskList[a[1]].ow;
o.push({id:a[1], diff:diff});
taskList[a[1]].ow += diff;
diff = posAfter[j] - posBefore[j]; // depends on position
if (curList.sort == 100) {
diff *= -1;
}
if (diff != 0) {
const taskId = j.split('_')[1];
if (j == itemId) {
diff = newWeight - taskList[taskId].ow; // just for new weight
}
o.push({id:taskId, diff:diff});
taskList[taskId].ow += diff;
}
}
@ -2403,7 +2510,9 @@ function moveTaskToList(taskId, listId)
taskList[item.id] = item;
var noteExpanded = (item.note != '' && $('#taskrow_'+item.id).is('.task-expanded')) ? 1 : 0;
$('#taskrow_'+item.id).replaceWith(_mtt.prepareTaskStr(item, noteExpanded));
if(curList.sort != 0) changeTaskOrder(item.id);
if (curList.sort != 0 && curList.sort != 100) {
changeTaskOrder(item.id);
}
refreshTaskCnt();
$('#taskrow_'+item.id).effect("highlight", {color:_mtt.theme.editTaskFlashColor}, 'normal', function(){$(this).css('display','')});
}
@ -2445,8 +2554,9 @@ function cmenuOnListRenamed(list)
$('#cmenu_list\\:'+list.id).text(list.name);
};
function cmenuOnListSelected(list)
function cmenuOnListSelected(a)
{
const list = a.list;
$('#cmenulistscontainer li').removeClass('mtt-item-disabled');
$('#cmenu_list\\:'+list.id).addClass('mtt-item-disabled').removeClass('mtt-list-hidden');
};
@ -2464,8 +2574,9 @@ function cmenuOnListHidden(list)
};
function tabmenuOnListSelected(list)
function tabmenuOnListSelected(a)
{
const list = a.list;
if (list.published) {
$('#btnPublish').addClass('mtt-item-checked');
$('#btnRssFeed').removeClass('mtt-item-disabled');
@ -2575,16 +2686,18 @@ function escapeHtml(str) {
function slmenuOnListsLoaded()
{
if(_mtt.menus.selectlist) {
if (_mtt.menus.selectlist) {
_mtt.menus.selectlist.destroy();
_mtt.menus.selectlist = null;
}
var s = '';
var all = tabLists.getAll();
for(var i in all) {
s += '<li id="slmenu_list:'+all[i].id+'" class="'+(all[i].id==curList.id?'mtt-item-checked':'')+' list-id-'+all[i].id+(all[i].hidden?' mtt-list-hidden':'')+'"><div class="menu-icon"></div><a href="'+ _mtt.urlForList(all[i])+ '">'+all[i].name+'</a></li>';
}
let s = '';
tabLists.getAll().forEach( (list) => {
const classChecked = (list.id == curList.id) ? 'mtt-item-checked' : '';
const classHidden = list.hidden ? 'mtt-list-hidden' : '';
s += `<li id="slmenu_list:${list.id}" class="list-id-${list.id} ${classChecked} ${classHidden}">
<div class="menu-icon"></div><a href="${_mtt.urlForList(list)}">${list.name}</a><div class="counter hidden"></div></li>`;
})
$('#slmenucontainer ul>.slmenu-lists-begin').nextAll().remove();
$('#slmenucontainer ul>.slmenu-lists-begin').after(s);
};
@ -2600,11 +2713,13 @@ function slmenuOnListAdded(list)
_mtt.menus.selectlist.destroy();
_mtt.menus.selectlist = null;
}
$('#slmenucontainer ul').append('<li id="slmenu_list:'+list.id+'" class="list-id-'+list.id+'"><div class="menu-icon"></div><a href="'+ _mtt.urlForList(list)+ '">'+list.name+'</a></li>');
$('#slmenucontainer ul').append(`<li id="slmenu_list:${list.id}" class="list-id-${list.id}">
<div class="menu-icon"></div><a href="${_mtt.urlForList(list)}">${list.name}</a><div class="counter hidden"></div></li>`);
};
function slmenuOnListSelected(list)
function slmenuOnListSelected(a)
{
const list = a.list;
$('#slmenucontainer li').removeClass('mtt-item-checked');
$('#slmenucontainer li.list-id-'+list.id).addClass('mtt-item-checked').removeClass('mtt-list-hidden');
@ -2718,37 +2833,134 @@ function newTaskCounter()
});
});
fetch(_mtt.apiUrl + 'tasks/newCounter', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'MTT-Token': _mtt.options.token,
},
body: JSON.stringify(params)
})
.then(response => response.json())
.then(json => {
if (json && json.total) {
_mtt.db.request("newTaskCounter", params, json => {
if (json && json.ok) {
let counters = {};
let curCounter = 0;
if (Array.isArray(json.tasks)) {
let curCounter = 0;
json.tasks.forEach((id) => {
if (!taskList[id]) {
curCounter++;
}
});
if (curCounter > 0) {
$('#list_'+curList.id).find('.counter').text(curCounter).removeClass('hidden');
}
}
counters[curList.id] = curCounter;
if (Array.isArray(json.lists)) {
json.lists.forEach((item) => {
$('#list_'+item.listId).find('.counter').text(item.counter).removeClass('hidden');
counters["" + item.listId] = +item.counter;
});
}
tabLists.getAll().forEach( (list) => {
if (!list.hidden || list.id != -1) {
setNewTaskCounterForList(list.id, counters[list.id]);
}
});
_mtt.doAction("newTaskCounterUpdated");
}
});
}
function setNewTaskCounterForList(listId, counter)
{
const list = tabLists.get(listId);
if (!list) return;
if (list.newTaskCounterOld) {
counter += list.newTaskCounterOld;
}
if (counter > 0) {
$('#list_' + listId).find('.counter').text(counter).removeClass('hidden');
$('#slmenucontainer li.list-id-' + listId).find('.counter').text(counter).removeClass('hidden');
list.newTaskCounter = counter;
} else {
$('#list_' + listId).find('.counter').text('').addClass('hidden');
$('#slmenucontainer li.list-id-' + listId).find('.counter').text('').addClass('hidden');
list.newTaskCounter = 0;
}
}
function newTaskCounterOnListSelected(a)
{
if (a.prevList && a.prevList.newTaskCounter) {
a.prevList.newTaskCounterOld = a.prevList.newTaskCounter;
}
}
/**
* Set favicon with number of new tasks
*/
function newTaskCounterUpdated()
{
// Calc a total number of new tasks in visible tabs
let total = 0;
tabLists.getAll().forEach( (list) => {
if (list.newTaskCounter && (!list.hidden || list.id != -1)) {
total += list.newTaskCounter;
}
});
// Restore original icon
if (total <= 0) {
const o = document.querySelectorAll('link[rel="icon"]');
let oType, oHref;
for (let i = 0; i < o.length; i++) {
if (o[i].dataset.ohref) {
oHref = o[i].dataset.ohref;
oType = o[i].dataset.otype;
o[i].parentNode.removeChild(o[i]);
}
}
if (oHref) {
const n = document.createElement('link');
n.setAttribute('rel', 'icon');
n.setAttribute('href', oHref);
n.setAttribute('type', oType);
document.querySelector('head').appendChild(n);
}
return;
}
// Draw new icon
const c = document.createElement('canvas');
c.height = c.width = 64;
const ctx = c.getContext('2d');
//filled circle in center
ctx.lineWidth = 4;
ctx.fillStyle = '#ff0000';
ctx.beginPath();
ctx.arc(c.width / 2, c.height / 2, c.width / 2 - 2, 0, 2 * Math.PI, false);
ctx.fill();
//number in center
ctx.font = '48px Helvetica';
ctx.fillStyle = '#ffffff';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText( total > 9 ? '9+' : total, 32, 32, 50);
// Save params of original icon
const o = document.querySelectorAll('link[rel="icon"]');
let oType, oHref;
for (let i = 0; i < o.length; i++) {
oHref = o[i].dataset.ohref;
oType = o[i].dataset.otype;
if (!oHref) {
oHref = o[i].getAttribute('href');
oType = o[i].getAttribute('type') || '';
}
o[i].parentNode.removeChild(o[i]);
}
// Set new icon
const n = document.createElement('link');
n.setAttribute('rel', 'icon');
n.setAttribute('href', c.toDataURL()); //"data:image/png;base64,......"
if (oHref) {
n.dataset.ohref = oHref;
n.dataset.otype = oType;
}
document.querySelector('head').appendChild(n);
}
/*
Errors and Info messages
*/
@ -2957,8 +3169,17 @@ function extensionSettingsAction(actionString, ext, formData)
$('#page_ajax .mtt-settings-table').html(json.html); //FIXME: maybe whole page?
return;
}
if (json.alertText) {
mttAlert(json.alertText);
return;
}
const callback = function() {
if (json.msg) flashInfo(json.msg, json.details);
if (json.alertTextOnLoad) {
mttAlert(json.alertTextOnLoad);
}
else if (json.msg) {
flashInfo(json.msg, json.details);
}
if (json.reload) {
setTimeout( function(){
//window.location.hash = '';

View file

@ -1,56 +1,72 @@
/*
This file is a part of myTinyTodo.
(C) Copyright 2010,2020,2022 Max Pozdeev <maxpozdeev@gmail.com>
(C) Copyright 2010,2020-2025 Max Pozdeev <maxpozdeev@gmail.com>
Licensed under the GNU GPL version 2 or any later. See file COPYRIGHT for details.
*/
(function(){
"use strict";
var mtt;
function MytinytodoAjaxApi(amtt)
/**
* @class
*/
function MytinytodoAjaxApi(props)
{
mtt = amtt;
if (typeof mytinytodo !== 'object') {
throw "mytinytodo global object is not found!";
}
this.useREST = true;
if (props.hasOwnProperty('useREST')) {
this.useREST = !!props.useREST;
}
}
window.MytinytodoAjaxApi = MytinytodoAjaxApi;
MytinytodoAjaxApi.prototype = {
MytinytodoAjaxApi.prototype =
{
/* required method */
request: function(action, params, callback)
{
if (!this[action]) throw "Unknown ApiDriver action: " + action;
this[action] (params, function(json){
if (json.denied) mtt.errorDenied();
if (callback) callback.call(mtt, json)
/**
* required method
* @param {string} action
* @param {Object.<string, any>} [params]
* @param {ApiDriverCallback} [callback]
*
* @callback ApiDriverCallback
* @param {object} json
*/
request(action, params, callback) {
if (typeof this[action] !== 'function') {
throw "Unknown ApiDriver action: " + action;
}
this[action](params, function(json){
if (json.denied) {
mytinytodo.errorDenied();
}
if (callback) {
callback.call(mytinytodo, json)
}
});
},
loadTasks: function(params, callback)
{
var q = '';
loadTasks(params, callback) {
let q = '';
if (params.search && params.search != '') q += '&s=' + encodeURIComponent(params.search);
if (params.tag && params.tag != '') q += '&t=' + encodeURIComponent(params.tag);
if (params.setCompl && params.setCompl != 0) q += '&setCompl=1';
if (params.saveSort && params.saveSort != 0) q += '&saveSort=1';
$.getJSON(mtt.apiUrl + 'tasks' + (mtt.apiUrl.indexOf('?') > -1 ? '&' : '?') + 'list='+params.list+'&compl='+params.compl+'&sort='+params.sort+q, callback);
$.getJSON(mytinytodo.apiUrl + 'tasks' + (mytinytodo.apiUrl.indexOf('?') > -1 ? '&' : '?') +
'list='+params.list+'&compl='+params.compl+'&sort='+params.sort+q,
callback);
},
newTask: function(params, callback)
{
newTask(params, callback) {
$.ajax({
url: mtt.apiUrl + 'tasks',
url: mytinytodo.apiUrl + 'tasks',
method: 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'simple',
action: 'newSimple',
list: params.list,
title: params.title,
tag: params.tag,
@ -61,14 +77,13 @@ MytinytodoAjaxApi.prototype =
},
fullNewTask: function(params, callback)
{
fullNewTask(params, callback) {
$.ajax({
url: mtt.apiUrl + 'tasks',
url: mytinytodo.apiUrl + 'tasks',
method: 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'full',
action: 'newFull',
list: params.list,
title: params.title,
note: params.note,
@ -83,11 +98,10 @@ MytinytodoAjaxApi.prototype =
},
editTask: function(params, callback)
{
editTask(params, callback) {
$.ajax({
url: mtt.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: 'PUT',
url: mytinytodo.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'edit',
@ -103,11 +117,10 @@ MytinytodoAjaxApi.prototype =
},
editNote: function(params, callback)
{
editNote(params, callback) {
$.ajax({
url: mtt.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: 'PUT',
url: mytinytodo.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'note',
@ -119,11 +132,10 @@ MytinytodoAjaxApi.prototype =
},
completeTask: function(params, callback)
{
completeTask(params, callback) {
$.ajax({
url: mtt.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: 'PUT',
url: mytinytodo.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'complete',
@ -135,22 +147,24 @@ MytinytodoAjaxApi.prototype =
},
deleteTask: function(params, callback)
{
deleteTask(params, callback) {
$.ajax({
url: mtt.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: 'DELETE',
url: mytinytodo.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: this.useREST ? 'DELETE' : 'POST',
contentType : 'application/json', // contentType and data are required if method is POST
data: JSON.stringify({
action: 'delete',
}),
success: callback,
dataType: 'json'
});
},
setTaskPriority: function(params, callback)
{
setTaskPriority(params, callback) {
$.ajax({
url: mtt.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: 'PUT',
url: mytinytodo.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'priority',
@ -161,11 +175,10 @@ MytinytodoAjaxApi.prototype =
});
},
changeOrder: function(params, callback)
{
changeOrder(params, callback) {
$.ajax({
url: mtt.apiUrl + 'tasks',
method: 'PUT',
url: mytinytodo.apiUrl + 'tasks',
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'order',
@ -176,21 +189,18 @@ MytinytodoAjaxApi.prototype =
});
},
suggestTags: function(params, callback)
{
$.getJSON(mtt.apiUrl + 'suggestTags', {list:params.list, q:params.q}, callback);
suggestTags(params, callback) {
$.getJSON(mytinytodo.apiUrl + 'suggestTags', {list:params.list, q:params.q}, callback);
},
tagCloud: function(params, callback)
{
$.getJSON(mtt.apiUrl + 'tagCloud/' + encodeURIComponent(params.list), callback);
tagCloud(params, callback) {
$.getJSON(mytinytodo.apiUrl + 'tagCloud/' + encodeURIComponent(params.list), callback);
},
moveTask: function(params, callback)
{
moveTask(params, callback) {
$.ajax({
url: mtt.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: 'PUT',
url: mytinytodo.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'move',
@ -202,10 +212,9 @@ MytinytodoAjaxApi.prototype =
});
},
parseTaskStr: function(params, callback)
{
parseTaskStr(params, callback) {
$.ajax({
url: mtt.apiUrl + 'tasks/parseTitle',
url: mytinytodo.apiUrl + 'tasks/parseTitle',
method: 'POST',
contentType : 'application/json',
data: JSON.stringify({
@ -218,20 +227,42 @@ MytinytodoAjaxApi.prototype =
});
},
// Lists
loadLists: function(params, callback)
{
$.getJSON(mtt.apiUrl + 'lists', callback);
newTaskCounter(params, callback) {
fetch(mytinytodo.apiUrl + 'tasks/newCounter', {
method: 'POST',
credentials: 'same-origin', // old browsers
headers: {
'Content-Type': 'application/json',
'MTT-Token': mytinytodo.options.token,
},
body: JSON.stringify(params)
})
.then((response) => {
if (!response.ok) throw response;
return response.json();
})
.catch((e) => {
if (e instanceof Error) console.log("newTaskCounter fetch error: ", e);
else console.log("newTaskCounter fetch error, HTTP status code: " + e.status);
})
.then(json => {
callback(json)
});
},
addList: function(params, callback)
{
// Lists
loadLists(params, callback) {
$.getJSON(mytinytodo.apiUrl + 'lists', callback);
},
addList(params, callback) {
$.ajax({
url: mtt.apiUrl + 'lists',
url: mytinytodo.apiUrl + 'lists',
method: 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'new',
name: params.name,
}),
success: callback,
@ -240,21 +271,23 @@ MytinytodoAjaxApi.prototype =
},
deleteList: function(params, callback)
{
deleteList(params, callback) {
$.ajax({
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'DELETE',
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'DELETE' : 'POST',
contentType : 'application/json', // contentType and data are required if method is POST
data: JSON.stringify({
action: 'delete',
}),
success: callback,
dataType: 'json'
});
},
renameList: function(params, callback)
{
renameList(params, callback) {
$.ajax({
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'rename',
@ -265,11 +298,10 @@ MytinytodoAjaxApi.prototype =
});
},
setSort: function(params, callback)
{
setSort(params, callback) {
$.ajax({
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'sort',
@ -281,11 +313,10 @@ MytinytodoAjaxApi.prototype =
});
},
publishList: function(params, callback)
{
publishList(params, callback) {
$.ajax({
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'publish',
@ -296,11 +327,10 @@ MytinytodoAjaxApi.prototype =
});
},
enableFeedKey: function(params, callback)
{
enableFeedKey(params, callback) {
$.ajax({
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'enableFeedKey',
@ -311,11 +341,10 @@ MytinytodoAjaxApi.prototype =
});
},
setShowNotesInList: function(params, callback)
{
setShowNotesInList(params, callback) {
$.ajax({
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'showNotes',
@ -326,11 +355,10 @@ MytinytodoAjaxApi.prototype =
});
},
setHideList: function(params, callback)
{
setHideList(params, callback) {
$.ajax({
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'hide',
@ -341,11 +369,10 @@ MytinytodoAjaxApi.prototype =
});
},
changeListOrder: function(params, callback)
{
changeListOrder(params, callback) {
$.ajax({
url: mtt.apiUrl + 'lists',
method: 'PUT',
url: mytinytodo.apiUrl + 'lists',
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'order',
@ -356,11 +383,10 @@ MytinytodoAjaxApi.prototype =
});
},
clearCompletedInList: function(params, callback)
{
clearCompletedInList(params, callback) {
$.ajax({
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'clearCompleted',
@ -372,10 +398,9 @@ MytinytodoAjaxApi.prototype =
/* Auth */
login: function(params, callback)
{
login(params, callback) {
$.ajax({
url: mtt.apiUrl + 'login',
url: mytinytodo.apiUrl + 'login',
method: 'POST',
contentType : 'application/json',
data: JSON.stringify({
@ -386,10 +411,9 @@ MytinytodoAjaxApi.prototype =
});
},
logout: function(params, callback)
{
logout(params, callback) {
$.ajax({
url: mtt.apiUrl + 'logout',
url: mytinytodo.apiUrl + 'logout',
method: 'POST',
success: callback,
dataType: 'json'
@ -397,5 +421,3 @@ MytinytodoAjaxApi.prototype =
}
};
})();

View file

@ -5,9 +5,8 @@
/* Dark mode */
/* prefers-color-scheme media query value detected in js part */
html[data-appearance=dark],
html[data-appearance=system][data-system-appearance=dark] {
/* prefers-color-scheme media query is used in html link tag */
:root {
color-scheme: dark;

View file

@ -1,7 +1,6 @@
@media print {
html { height:0; }
body { height:0; min-height:0; margin:0; }
html,body { height:auto; }
h2 { display: none; }
h3 { border-bottom:2px solid #777777; }
#toolbar { display: none; }
@ -10,8 +9,9 @@
.mtt-tab { display:none; }
.mtt-tab.mtt-tab-selected { display:block; border:none; background:none; margin:0; }
.mtt-tab.mtt-tab-selected a { padding:0; display:inline-block; height:auto; }
.mtt-tab.mtt-tab-selected .title-block { display:inline-block; }
.mtt-tab.mtt-tab-selected .list-action { display:none; }
.mtt-tab a span { text-align:left; padding:0; max-width:none; font-size:1.3rem; color:#000; }
.mtt-tab.mtt-tab-selected .title { text-align:left; padding:0; margin:0; max-width:none; font-size:1.3rem; color:#000; }
.mtt-tabs-new-button { display:none; }
#tabs_buttons { display:none; }

View file

@ -153,7 +153,7 @@ body, td, th, input, textarea, select, button {
width:100%;
max-width:1100px;
padding:8px;
margin-bottom:8px;
margin-bottom: 1rem;
box-sizing: border-box;
}
@ -176,7 +176,13 @@ body::after {
content:url(images/logo-loading.gif);
}
h3.page-title { margin:0; border-bottom:2px solid var(--color-content-delimiter); margin-bottom:10px; padding:0.6rem 0; font-size:1.1rem; }
h3.page-title {
margin:0;
border-bottom:2px solid var(--color-content-delimiter);
margin-bottom:1rem;
padding:0.6rem 0;
font-size:1.1rem;
}
a { color: var(--color-link); cursor:pointer; text-decoration:underline; }
.topblock { display:flex; align-items:flex-start; margin-bottom:1rem; }
@ -600,12 +606,15 @@ li.task-row.task-expanded .task-toggle { transform:rotate(90deg); }
background-color: var(--color-tasklist-row); /* ?? */
position:relative; /* for z-index */
}
#mtt:not(.touch-device) #tasklist li.task-row:hover,
/*#mtt:not(.touch-device) #tasklist li.task-row:hover,*/
#mtt:not(.touch-device) #tasklist li.task-row.menu-active {
z-index: 1;
box-shadow: 0 0 2px var(--color-tasklisk-hover-shadow);
border-radius: 5px;
}
#mtt:not(.touch-device) #tasklist li.task-row.menu-active:not(.task-expanded) {
border-bottom-color: transparent;
}
#tasklist .task-block {
display: flex;
justify-content: flex-start;
@ -616,6 +625,9 @@ li.task-row.task-expanded .task-toggle { transform:rotate(90deg); }
border:1px solid var(--color-tasklist-row-expanded-border);
border-radius: 3px;
}
#tasklist li.task-row:not(.task-expanded):has(+ li.task-row.task-expanded) {
border-bottom-color: transparent;
}
#tasklist li.task-row.task-has-note.task-expanded .task-block {
border-bottom: 1px solid var(--color-tasklist-row-inter-border);
}
@ -649,14 +661,15 @@ li.task-row.task-expanded .task-toggle { transform:rotate(90deg); }
margin-top: 0.2rem;
display: none;
}
.task-id {
/*display: none;*/
.task-id::after {
content: ' · '; /* '&middot;' */
}
#mtt.show-date .task-date {
display: block;
}
#mtt.show-date.date-inline .task-date {
display: inline;
display: inline-block; /* for RTL */
margin:0;
margin-left:3px;
}
.task-through { overflow:hidden; flex-grow:1; }
@ -678,7 +691,7 @@ li.task-row.task-expanded .task-toggle { transform:rotate(90deg); }
}
.task-tags {
margin:0px 3px;
display: inline-block; /* for RTL */
display: inline;
}
.task-tags:empty {
margin:0;
@ -701,6 +714,7 @@ li.task-row.task-completed .duedate { /*font-size:0.8rem;*/ display:none; }
#tasklist li.task-row.past .duedate { color: var(--color-duedate-past); }
#tasklist li.task-row.task-completed { opacity:0.6; }
#tasklist li.task-row.task-completed .task-through { text-decoration:line-through; }
#tasklist li.task-row.task-completed:hover { opacity:1.0; }
#tasklist li.task-row.not-in-tagpreview {
@ -764,13 +778,12 @@ li.task-row:hover .taskactionbtn {
word-wrap:break-word;
}
li.task-row.task-expanded .task-note-block { display:block; }
li.task-row.task-completed .task-note-block .task-note { text-decoration:line-through; }
.task-note-area { display:none; margin-bottom:5px; }
.task-note-area textarea { color:var(--color-text-reduced); width:100%; display:block; height:65px; }
.task-note-actions { font-size:0.8rem; }
.hidden { display:none; }
.invisible { visibility:hidden; }
.in500 { width:500px; color: var(--color-text-reduced); }
.in100 { width:100px; color: var(--color-text-reduced); }
.task-note a { color: var(--color-tasklist-note-link); }
.task-note a:hover { color: var(--color-tasklist-link-hover) }
@ -797,23 +810,43 @@ li.task-row.task-expanded .task-note-block { display:block; }
text-align: center;
}
.form-row { margin-top:0.6rem; }
.form-container {
display: flex;
flex-wrap: wrap;
}
.form-row {
margin-top:0.6rem;
}
.form-row-short {
margin-right:12px;
}
.form-row:not(.form-row-short) {
width:100%;
}
.form-row .h {
font-weight:bold;
color: var(--color-text-reduced);
}
.form-row div.h { margin-bottom:3px; }
.form-row-short-end { clear:both; }
#page_taskedit .form-row .in500 { width:100%; box-sizing:border-box; }
#page_taskedit .form-row textarea.in500 {
height:300px;
.form-row div.h {
margin-bottom:3px;
}
.form-input {
color: var(--color-text-reduced);
}
.form-input.in100 {
width:100px;
}
.form-input.inmax {
width:100%;
box-sizing:border-box;
}
textarea.form-input.inmax {
height:280px;
font-size:13px;
font-family: ui-monospace,Consolas,"SF Mono",Menlo,"Liberation Mono",monospace;
white-space: pre;
padding: 5px;
}
#page_taskedit .form-row-short { float:left; margin-right:12px; }
.alltags-cell { width:1%; white-space:nowrap; padding-left:5px; }
#page_taskedit.mtt-inadd .mtt-inedit { display:none; }
#page_taskedit.mtt-inedit .mtt-inadd { display:none; }
@ -836,6 +869,8 @@ li.task-row.task-expanded .task-note-block { display:block; }
#page_taskviewer .container .left {
flex-grow: 1;
min-width: 0; /* to limit long text*/
border-right: 1px solid var(--color-tasklist-row-expanded-border);
padding-right: 0.5rem;
}
#page_taskviewer .container .right {
min-width:300px;
@ -876,6 +911,9 @@ li.task-row.task-expanded .task-note-block { display:block; }
flex-wrap: wrap;
max-width: 100%;
}
#mtt.readonly #taskviewer_edit_btn {
display: none;
}
/* autocomplete */
.ui-helper-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
@ -940,6 +978,9 @@ li.task-row.task-expanded .task-note-block { display:block; }
#tagcloudAllLists:disabled + label {
opacity: 0.6;
}
#tagcloudSearch {
margin-left: 0.5rem;
}
#tagcloudcancel span {
mask: var(--svg-closetag) no-repeat; -webkit-mask: var(--svg-closetag) no-repeat;
background-color: var(--color-btn-reduced);
@ -1032,7 +1073,23 @@ li.task-row.task-expanded .task-note-block { display:block; }
mask: var(--svg-arr-right) no-repeat; -webkit-mask: var(--svg-arr-right) no-repeat;
background-color: var(--color-btn-default);
}
.ui-datepicker select {
appearance: none;
-webkit-appearance: none; -moz-appearance: none;
background: transparent var(--svg-select) no-repeat top 2px right 4px;
background-size: 1rem 1rem;
padding: 1px 3px;
padding-right: calc(1rem + 7px);
border: 1px solid var(--color-border-default);
border-radius: 2px;
color: var(--color-text-default);
margin: 0 2px;
}
.ui-datepicker select:focus {
outline:none;
/*border-color: var(--color-border-focus);
box-shadow:0 0 0 2px var(--color-border-focus-shadow);*/
}
.mtt-menu-button {
user-select: none;
@ -1106,6 +1163,15 @@ li.mtt-menu-indicator .submenu-icon {
mask: var(--svg-arr-right) no-repeat; -webkit-mask: var(--svg-arr-right) no-repeat;
background-color: var(--color-btn-default);
}
.mtt-menu-container .counter {
position:absolute; right:6px; top:50%; margin-top:-8px;
height: 16px; min-width:16px;
border-radius: 1rem;
font-size: 0.8rem;
text-align: center;
background-color: #686868; /* #de5141 */
color: white;
}
li.mtt-item-hidden { display:none; }
#slmenucontainer li.mtt-list-hidden a { font-style:italic; }
@ -1139,14 +1205,19 @@ li.mtt-item-hidden { display:none; }
vertical-align:top;
display: flex;
}
.mtt-settings-table .tr.group-header {
border-bottom: none !important;
padding-bottom: 0 !important;
background-color: unset !important;
}
.mtt-settings-table .group {
margin-top: 0.5rem;
margin-top: 0.75rem;
margin-bottom: 0.5rem;
border-radius: 1rem;
background-color: var(--color-settings-row);
}
.mtt-settings-table .group .tr {
margin: 0 1rem;
margin: 0 10px;
padding: 1rem 0;
}
.mtt-settings-table .group .th {
@ -1162,8 +1233,12 @@ li.mtt-item-hidden { display:none; }
padding: 0 10px;
}
.mtt-settings-table .th {
width: 30%;
font-weight: bold;
width: 30%;
font-weight: bold;
font-weight: 600;
}
.mtt-settings-table .group-header .th {
font-size: 0.9rem;
}
.mtt-settings-table .td {
flex-grow: 1;
@ -1286,10 +1361,12 @@ li.mtt-item-hidden { display:none; }
font-size: 16px;
-webkit-text-size-adjust: 100%; /* Dont increase font-size in horizontal orientation on ios */
}
#page_taskedit .form-row textarea.in500 { font-size: 14px; }
textarea.form-input.inmax { font-size: 14px; }
}
/* narrow screens */
/* ========== narrow screens =========*/
@media only screen and (max-width: 600px) {
#mtt { padding: 15px 8px 0px; }
@ -1331,6 +1408,10 @@ li.mtt-item-hidden { display:none; }
#toolbar.mtt-insearch .searchbox-c { width:100%; max-width:100%; }
#search { padding:5px 20px; border-radius:15px; }
#tagcloudSearch {
margin-top: 0.5rem;
}
.task-date {
white-space: nowrap;
overflow: hidden;
@ -1358,11 +1439,13 @@ li.mtt-item-hidden { display:none; }
.task-toggle { display:none; }
#tasklist .mtt-task-placeholder { line-height:1rem; padding-top:0.6rem; padding-bottom:0.6rem; }
#tasklist .ui-sortable-helper { box-shadow:0px 0px 3px #555; }
#tasklist .ui-sortable-helper { box-shadow:0px 0px 3px #555; opacity: 0.9; }
#tasklist .ui-sortable-helper .task-left { visibility: hidden }
#tasklist .ui-sortable-helper .task-actions > * { visibility: hidden }
#page_taskedit { max-width:100%; border:none; position:static; padding:0; }
#page_taskedit .form-table { width:100%; }
#page_taskedit .form-row textarea { height: 70px; }
#page_taskedit .form-row textarea { height: 150px; }
#loading { padding:0px; padding-top:1px; padding-right:1px; height:16px; overflow:hidden; }
@ -1370,11 +1453,18 @@ li.mtt-item-hidden { display:none; }
.mtt-settings-table .in350 { min-width:50px; width:100%; }
.mtt-notes-showhide { display:none; }
.mtt-menu-container li { padding-top:0.3rem; padding-bottom:0.3rem; }
.mtt-menu-container li {
padding-top: 0.4rem;
padding-bottom: 0.4rem;
}
#page_taskviewer .container {
flex-direction: column;
}
#page_taskviewer .container .left {
border-right: none;
padding-right: 0;
}
#page_taskviewer .container .right {
max-width: unset;
padding-left: 0;
@ -1387,7 +1477,8 @@ li.mtt-item-hidden { display:none; }
}
#page_taskviewer .note,
#page_taskviewer .no-note {
padding-bottom:10px;
padding-bottom: 1rem;
margin-bottom: 1rem;
border-bottom: 2px solid var(--color-tasklist-row-expanded-border);
}
@ -1398,15 +1489,22 @@ li.mtt-item-hidden { display:none; }
padding:10px 15px;
margin-bottom: 5px;
}
.mtt-settings-table .group {
background-color: var(--color-settings-row);
}
.mtt-settings-table .group .tr {
border-radius: 0;
padding: 1rem 0;
margin: 0 1rem;
padding: 1rem 1rem;
margin: 0 0;
margin-bottom: 5px;
background-color: unset;
}
.mtt-settings-table .group .tr:not(:last-child) {
border-bottom:1px solid var(--color-border-default);
}
.mtt-settings-table .group .th {
padding: 0;
}
.mtt-settings-table .th {
width: auto;
padding-left: 0px;
@ -1418,7 +1516,12 @@ li.mtt-item-hidden { display:none; }
.mtt-settings-table .td.extensions {
line-height: 2em;
}
.mtt-settings-table input , .mtt-settings-table select, .mtt-settings-table label { margin-top:5px; background-color: var(--color-settings-row); }
.mtt-settings-table input,
.mtt-settings-table select,
.mtt-settings-table label {
margin-top:5px;
box-sizing: border-box;
}
.form-bottom-buttons > * {
padding: 7px;

View file

@ -1,13 +1,23 @@
body { direction:rtl; }
h2 { padding-left:10px; padding-right:0px; }
.topblock h2 {
background-position: right;
padding-left: 10px;
padding-right: 30px;
}
#loading { margin-left:6px; margin-right:0px; }
.bar-menu { text-align: left; }
.bar-menu > * {
margin-right: 10px;
margin-left: unset;
}
.mtt-tab { margin-left:3px; margin-right:0px; border-top-right-radius:0px; border-top-left-radius:8px; }
.mtt-tabs-new-button { border-top-right-radius:0px; border-top-left-radius:8px; }
.mtt-tabs-select-button>span { transform:rotateY(180deg); }
#task { padding-left:20px; padding-right:4px; }
.mtt-taskbox-icon { left:2px; right:auto; transform:rotateY(180deg); }
#newtask_adv { margin-left:0; margin-right:0.5rem; }
#newtask_adv { margin-left:0; margin-right:0.5rem; transform:rotateY(180deg); }
.mtt-searchbox-icon.mtt-icon-search { right:4px; left:auto; }
.mtt-searchbox-icon.mtt-icon-cancelsearch { left:4px; right:auto; }
@ -27,10 +37,9 @@ h2 { padding-left:10px; padding-right:0px; }
.duedate:before { content:'\20\2190\20'; }
#tagcloud { box-shadow:-1px 2px 5px rgba(0,0,0,0.5); }
#tagcloudcancel { float:left; }
#taskedit-date { float:left; }
#page_taskedit .form-row-short { float:right; margin-left:12px; margin-right:0; }
h3.page-title a.mtt-back-button { transform:rotate(180deg); }
.form-row-short { margin-left:12px; margin-right:0; }
.alltags-cell { padding-left:0; padding-right:5px; }
.mtt-menu-container { box-shadow:-1px 2px 5px rgba(0,0,0,0.5); }

5
src/ext/.htaccess Normal file
View file

@ -0,0 +1,5 @@
<FilesMatch "\.(json|md|MD)$">
Order deny,allow
Deny from all
</FilesMatch>

View file

@ -2,7 +2,7 @@
/*
This file is a part of myTinyTodo.
(C) Copyright 2023 Max Pozdeev <maxpozdeev@gmail.com>
(C) Copyright 2023-2025 Max Pozdeev <maxpozdeev@gmail.com>
Licensed under the GNU GPL version 2 or any later. See file COPYRIGHT for details.
*/
@ -86,11 +86,9 @@ class Backup
}
$db = \DBConnection::instance();
$props = null;
if ($db::DBTYPE == \DBConnection::DBTYPE_MYSQL) {
$autoinc = $this->getMysqlTableAutoIncrement($table);
if ($autoinc != '') {
$props = ['auto_increment' => $autoinc];
}
$autoinc = $this->getTableAutoIncrement($table);
if ($autoinc != '') {
$props = ['auto_increment' => $autoinc];
}
$this->writeOpeningTag($group, $props);
$q = $db->dq("SELECT * FROM $table");
@ -120,11 +118,26 @@ class Backup
$this->writeClosingTag($entity);
}
function getMysqlTableAutoIncrement(string $table): string
function getTableAutoIncrement($table): string
{
$db = \DBConnection::instance();
$r = $db->sqa("SHOW TABLE STATUS WHERE Name=?", [$table]);
return (string)$r['Auto_increment'] ?? '';
if ($db::DBTYPE == \DBConnection::DBTYPE_MYSQL) {
$r = $db->sqa("SHOW TABLE STATUS WHERE Name=?", [$table]);
return (string)$r['Auto_increment'] ?? '';
}
else if ($db::DBTYPE == \DBConnection::DBTYPE_SQLITE) {
$seq = (int)$db->sq("SELECT seq FROM sqlite_sequence WHERE name=?", [$table]);
if ($seq > 0)
return (string)$seq;
}
else if ($db::DBTYPE == \DBConnection::DBTYPE_POSTGRES) {
if ($db->tableFieldExists($table, 'id')) {
$v = (int)$db->sq("SELECT last_value FROM ". $table. '_id_seq');
if ($v > 0)
return (string)$v;
}
}
return '';
}

View file

@ -31,8 +31,9 @@ class Controller extends \ApiController
$this->response->data = [
'total' => 1,
'ok' => true,
'msg' => __("backup.done"),
'details' => ''
'alertTextOnLoad' => __("backup.done"),
];
}
@ -118,12 +119,17 @@ class Controller extends \ApiController
];
return;
}
$html = "<pre>". htmlspecialchars($check->report). "</pre>";
$this->response->data = [
'total' => 1,
'ok' => true,
'msg' => __("backup.done"),
'html' => $html,
];
if ($check->report == 'OK') {
$this->response->data['alertText'] = "OK";
}
else {
$this->response->data['html'] = "<pre>". htmlspecialchars($check->report). "</pre>";
}
}
function postRepairInconsistency()
@ -141,7 +147,9 @@ class Controller extends \ApiController
}
$this->response->data = [
'total' => 1,
'ok' => true,
'msg' => __("backup.done"),
'alertText' => __("backup.done"),
];
}

View file

@ -2,7 +2,7 @@
/*
This file is a part of myTinyTodo.
(C) Copyright 2023 Max Pozdeev <maxpozdeev@gmail.com>
(C) Copyright 2023-2025 Max Pozdeev <maxpozdeev@gmail.com>
Licensed under the GNU GPL version 2 or any later. See file COPYRIGHT for details.
*/
@ -217,6 +217,9 @@ class Restore
case DBConnection::DBTYPE_POSTGRES:
$db->ex("ALTER TABLE {$db->prefix}$table ALTER COLUMN id RESTART WITH ". (int)$autoinc);
break;
case DBConnection::DBTYPE_SQLITE:
$db->ex("UPDATE sqlite_sequence SET seq=? WHERE name=?", [$autoinc, $db->prefix. $table]);
break;
default:
break;
}
@ -232,8 +235,9 @@ class Restore
$db->ex("TRUNCATE TABLE $table RESTART IDENTITY");
}
else {
// we do not use TRUNCATE on mysql due to autocommit
// sqlite has truncate optimizer
# - we do not use TRUNCATE on mysql due to autocommit
# - sqlite has truncate optimizer while delete all to make it faster
# - no need to reset auto_increment sequence before inserting lower ids
$db->ex("DELETE FROM $table");
}
}

View file

@ -1,6 +1,6 @@
{
"bundleId": "backup",
"name": "Backup",
"version": "0.9",
"version": "1.1",
"description": "Backup"
}

View file

@ -65,7 +65,7 @@ class BackupExtension extends MTTExtension implements MTTExtensionSettingsInterf
$filename = MTTPATH. 'db/backup.xml';
if (file_exists($filename)) {
$time = filemtime($filename);
$lastBackup = htmlspecialchars( sprintf($e('backup.last_backup'), formatTime(Config::get('dateformat'). " H:m:s", $time)) );
$lastBackup = htmlspecialchars( sprintf($e('backup.last_backup'), formatTime(Config::get('dateformat'). " H:i:s", $time)) );
}
else {
$downloadDisabled = 'disabled';
@ -95,7 +95,7 @@ function onBackupFileChange(el) {
<div class="descr">{$e('backup.d_inconsistency')}</div>
</div>
<div class="td">
<button type=button data-ext-settings-action="post:checkInconsistency:file" data-ext="$ext"> {$e('backup.check')} </button> &nbsp;
<button type=button data-ext-settings-action="post:checkInconsistency" data-ext="$ext"> {$e('backup.check')} </button> &nbsp;
<button type=button data-ext-settings-action="post:repairInconsistency" data-ext="$ext"> {$e('backup.repair')} </button> <br>
</div>
</div>

0
src/ext/index.html Normal file
View file

View file

@ -20,7 +20,7 @@ class Sender
function __construct(array $prefs, bool $useCli = false)
{
$this->prefs = $prefs;
if ($useCli && function_exists('pcntl_fork')) {
if ($useCli && function_exists('pcntl_fork') && function_exists('posix_setsid')) {
$this->cli = true;
}
}
@ -193,7 +193,7 @@ class Sender
$host = parse_url(get_unsafe_mttinfo('url'), PHP_URL_HOST);
$host = preg_replace('/^(www\.)/', '', $host);
//$host = gethostname();
if (function_exists('posix_getuid') && false !== ($userinfo = posix_getpwuid(posix_getuid())) ) {
if (function_exists('posix_getpwuid') && false !== ($userinfo = posix_getpwuid(posix_getuid())) ) {
return $userinfo['name']. '@'. $host;
}
return "mytinytodo@$host";

View file

@ -2,7 +2,7 @@
/*
This file is a part of myTinyTodo.
(C) Copyright 2022 Max Pozdeev <maxpozdeev@gmail.com>
(C) Copyright 2022-2023 Max Pozdeev <maxpozdeev@gmail.com>
Licensed under the GNU GPL version 2 or any later. See file COPYRIGHT for details.
*/
@ -16,6 +16,10 @@ if (!function_exists('pcntl_fork')) {
error_log("Required PHP module is not found: pcntl");
exit(-2);
}
if (!function_exists('posix_setsid')) {
error_log("Required PHP module is not found: posix");
exit(-2);
}
$dontStartSession = 1;
require(__DIR__.'/../../init.php');

View file

@ -1,6 +1,6 @@
{
"bundleId": "notifications",
"name": "Notifications",
"version": "1.1",
"version": "1.2.1",
"description": "Notify about new tasks and lists on e-mail or telegram"
}

View file

@ -0,0 +1,30 @@
{
"ext.notifications.name": "Benachrichtigungen",
"notifications.urlconfigwarning": "Aktivieren Sie die PHP-Direktive 'allow_url_fopen', um Telegram-Benachrichtigungen zu verwenden.",
"notifications.check": "Check",
"notifications.bot_not_configured": "Bot ist nicht konfiguriert",
"notifications.g_email": "E-Mail",
"notifications.h_email": "E-Mail:",
"notifications.d_email": "Mehrere Adressen mit Komma trennen.",
"notifications.h_mailfrom": "Mail von:",
"notifications.d_mailfrom": "Diese E-Mail als Absenderadresse verwenden.",
"notifications.g_telegram": "Telegram",
"notifications.h_token": "Bot-Token:",
"notifications.d_token": "Telegram Bot API-Token von @BotFather",
"notifications.h_active_chats": "Aktive Chats:",
"notifications.d_active_chats": "Anzahl der Chats, bei denen der Bot Benachrichtigungen sendet.",
"notifications.deactivate_all": "Alle deaktivieren",
"notifications.h_new_chat": "Neuer Chat:",
"notifications.d_new_chat": "Starte eine neue Unterhaltung mit dem Bot, sende diesen Code an den Chat und klicke hier auf "Überprüfen".",
"notifications.saved": "Gesichert",
"notifications.invalid_email": "Ungültige E-Mail Adresse",
"notifications.no_bot_info": "Kann keine Bot-Informationen erhalten, Token scheint ungültig zu sein",
"notifications.all_chats_deactivated": "Alle Chats deaktiviert",
"notifications.no_new_chats": "Keine neuen Chats": "Keine neuen Chats",
"notifications.already_active": "Bereits aktiv",
"notifications.please_send": "Bitte senden Sie einen Code zur Aktivierung",
"notifications.code_not_set": "Code ist nicht gesetzt",
"notifications.code_expired": "Der Code ist abgelaufen",
"notifications.code_wrong": "Falscher Code",
"notifications.activated": "Aktiviert"
}

View file

@ -3,11 +3,12 @@
"notifications.urlconfigwarning": "Enable PHP 'allow_url_fopen' directive to use Telegram notifications.",
"notifications.check": "Check",
"notifications.bot_not_configured": "Bot is not configured",
"notifications.h_email": "E-Mail:",
"notifications.g_email": "E-Mail",
"notifications.h_email": "E-mail:",
"notifications.d_email": "Separate multiple addresses with comma.",
"notifications.h_mailfrom": "Mail from:",
"notifications.d_mailfrom": "Use this e-mail as sender's address.",
"notifications.h_telegram": "Telegram",
"notifications.g_telegram": "Telegram",
"notifications.h_token": "Bot token:",
"notifications.d_token": "Telegram Bot API token from @BotFather.",
"notifications.h_active_chats": "Active chats:",

View file

@ -3,11 +3,12 @@
"notifications.urlconfigwarning": "Для использования Telegram требуется включить директиву 'allow_url_fopen' в настройках PHP .",
"notifications.check": "Проверить",
"notifications.bot_not_configured": "Бот не настроен",
"notifications.h_email": "E-Mail:",
"notifications.g_email": "E-Mail",
"notifications.h_email": "E-mail:",
"notifications.d_email": "Разделите несколько адресов c помощью запятой.",
"notifications.h_mailfrom": "Адрес отправителя:",
"notifications.d_mailfrom": "Этот адрес будет указан как адрес отправителя в письмах с уведомлениями.",
"notifications.h_telegram": "Telegram",
"notifications.g_telegram": "Telegram",
"notifications.h_token": "Токен для бота:",
"notifications.d_token": "Токен для телеграм-бота, полученный от @BotFather.",
"notifications.h_active_chats": "Активные чаты:",

View file

@ -113,6 +113,11 @@ class NotificationsExtension extends MTTExtension implements MTTHttpApiExtender,
return
<<<EOD
$warning
<div class="tr group-header">
<div class="th"> {$e('notifications.g_email')} </div>
</div>
<div class="group">
<div class="tr">
<div class="th"> {$e('notifications.h_email')}
<div class="descr">{$e('notifications.d_email')}</div>
@ -125,9 +130,12 @@ $warning
</div>
<div class="td"> <input name="mailfrom" value="$mailfrom" class="in350" autocomplete="email" placeholder="$mailfromDefault"> </div>
</div>
<div class="tr">
<div class="th"> {$e('notifications.h_telegram')} </div>
</div><!--/group-->
<div class="tr group-header">
<div class="th"> {$e('notifications.g_telegram')} </div>
</div>
<div class="group">
<div class="tr">
<div class="th"> {$e('notifications.h_token')}
<div class="descr">{$e('notifications.d_token')}</div>
@ -146,6 +154,7 @@ $warning
</div>
<div class="td"> $newChat </div>
</div>
</div><!--/group-->
EOD;
}

Some files were not shown because too many files have changed in this diff Show more