Compare commits

..

No commits in common. "master" and "v1.8-beta" have entirely different histories.

135 changed files with 2310 additions and 2490 deletions

View file

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

2
.gitignore vendored
View file

@ -1,8 +1,6 @@
.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,22 +1,3 @@
# myTinyTodo
Your tiny todo list
myTinyTodo
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,9 +43,7 @@ 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
@ -72,7 +70,7 @@ if (is_dir('src/ext')) {
}
chdir('../ext2');
if ($extCount > 0) {
`tar --no-xattrs -czf ../ext/extensions.tar.gz *`; #OS dep.!!!
`tar -czf ../ext/extensions.tar.gz *`; #OS dep.!!!
}
chdir('../..');
deleteTreeIfDir('src/ext2');
@ -82,7 +80,7 @@ if (is_dir('src/ext')) {
rename('src', 'mytinytodo') or die("Cant rename 'src'\n");
`tar --no-xattrs -czf mytinytodo.tar.gz mytinytodo`; #OS dep.!!!
`tar -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,24 +1,12 @@
{
"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": {
"php": ">=7.2",
"ext-mbstring": "*",
"erusev/parsedown": "1.7.x-dev#f7285e7",
"symfony/polyfill-intl-normalizer": "^1.31"
"erusev/parsedown": "^1.7",
"symfony/polyfill-intl-normalizer": "^1.28"
},
"require-dev": {
"league/commonmark": "^2.6"
"league/commonmark": "^2.4"
}
}

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

View file

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

1
docker/dev/.gitignore vendored Normal file
View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,23 @@
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

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

View file

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

View file

@ -0,0 +1,59 @@
# 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

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

View file

@ -0,0 +1,17 @@
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

@ -0,0 +1,58 @@
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

@ -0,0 +1,13 @@
[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

@ -0,0 +1,10 @@

; 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

@ -0,0 +1,42 @@
;; 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

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

View file

@ -0,0 +1,47 @@
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

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

View file

@ -0,0 +1,47 @@
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

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

View file

@ -0,0 +1,45 @@
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

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

View file

@ -0,0 +1,18 @@
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

@ -0,0 +1,17 @@
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

@ -0,0 +1,11 @@

; 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

@ -0,0 +1,34 @@
;; 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

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

View file

@ -0,0 +1,15 @@
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

@ -0,0 +1,17 @@
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

@ -0,0 +1,9 @@

; 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

@ -0,0 +1,34 @@
;; 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

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

View file

@ -0,0 +1,11 @@
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

@ -0,0 +1,37 @@
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

@ -0,0 +1,10 @@

; 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

@ -0,0 +1,42 @@
;; 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

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

View file

@ -0,0 +1,45 @@
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

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

View file

@ -0,0 +1,15 @@
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

@ -0,0 +1,16 @@
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

@ -0,0 +1,9 @@

; 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

@ -0,0 +1,42 @@
;; 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

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

View file

@ -0,0 +1,56 @@
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

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

View file

@ -0,0 +1,16 @@
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

@ -0,0 +1,16 @@
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

@ -0,0 +1,9 @@

; 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

@ -0,0 +1,42 @@
;; 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

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

View file

@ -0,0 +1,58 @@
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

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

View file

@ -0,0 +1,17 @@
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

@ -0,0 +1,40 @@
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

@ -0,0 +1,13 @@
[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

@ -0,0 +1,12 @@

; 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

@ -0,0 +1,42 @@
;; 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

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

View file

@ -0,0 +1,17 @@
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

@ -0,0 +1,19 @@
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

@ -0,0 +1,9 @@

; 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

@ -0,0 +1,42 @@
;; 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

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

View file

@ -0,0 +1,15 @@
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

@ -0,0 +1,19 @@
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

@ -0,0 +1,11 @@

; 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

@ -0,0 +1,42 @@
;; 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

8
docker/dev/readme.md Normal file
View file

@ -0,0 +1,8 @@
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,29 +1,12 @@
# For REST API in Apache
# For 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>
# 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
# For Nginx set something like this:
# 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-2025 Max Pozdeev <maxpozdeev@gmail.com>
Copyright: 2009-2011,2019-2023 Max Pozdeev <maxpozdeev@gmail.com>
License: GPL version 2 or any later (see LICENSE file)
@ -48,12 +48,7 @@ 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 file content/theme/images/COPYRIGHT for details.
See files content/themes/images/COPYRIGHT for details.

View file

@ -32,7 +32,6 @@ $endpoints = array(
'GET' => [ ListsController::class , 'getId' ],
'PUT' => [ ListsController::class , 'putId' ],
'DELETE' => [ ListsController::class , 'deleteId' ],
'POST' => [ ListsController::class , 'putId' ], //compatibility
],
'/tasks' => [
'GET' => [ TasksController::class , 'get' ],
@ -42,7 +41,6 @@ $endpoints = array(
'/tasks/(-?\d+)' => [
'PUT' => [ TasksController::class , 'putId' ],
'DELETE' => [ TasksController::class , 'deleteId' ],
'POST' => [ TasksController::class , 'putId' ], //compatibility
],
'/tasks/parseTitle' => [
'POST' => [ TasksController::class , 'postTitleParse' ],
@ -62,7 +60,6 @@ $endpoints = array(
'/ext-settings/(.+)' => [
'GET' => [ ExtSettingsController::class , 'get' ],
'PUT' => [ ExtSettingsController::class , 'put' ],
'POST' => [ ExtSettingsController::class , 'put' ], //compatibility
]
);
@ -151,7 +148,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) {
elseif ($errno==E_WARNING || $errno==E_CORE_WARNING || $errno==E_COMPILE_WARNING || $errno==E_USER_WARNING || $errno==E_STRICT) {
if (error_reporting() & $errno) $error = 'Warning'; else return;
}
elseif ($errno==E_NOTICE || $errno==E_USER_NOTICE || $errno==E_DEPRECATED || $errno==E_USER_DEPRECATED) {
@ -200,7 +197,6 @@ 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.1.5 as modified by RWAP Software
* jQuery UI Touch Punch 1.0.8 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,30 +31,31 @@
}(function ($) {
// Detect touch support - Windows Surface devices and other touch devices
$.mspointer = window.navigator.msPointerEnabled;
$.touch = ( 'ontouchstart' in document
|| 'ontouchstart' in window
|| window.TouchEvent
|| (window.DocumentTouch && document instanceof DocumentTouch)
|| navigator.maxTouchPoints > 0
|| navigator.msMaxTouchPoints > 0
$.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
);
// Ignore browsers without touch or mouse support
if ((!$.touch && !$.mspointer) || !$.ui.mouse) {
return;
if ((!$.support.touch && !$.support.mspointer) || !$.ui.mouse) {
return;
}
let mouseProto = $.ui.mouse.prototype,
var mouseProto = $.ui.mouse.prototype,
_mouseInit = mouseProto._mouseInit,
_mouseDestroy = mouseProto._mouseDestroy,
touchHandled, lastClickTime = 0;
touchHandled;
let delay = 300,
var delay = 300,
delayTimer,
delayEvent,
delayStarted = false,
delayFinished = false,
lastClickTimeStamp = 0,
lastClickCoord;
@ -81,26 +82,32 @@
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();
}
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
});
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
);
// Dispatch the simulated event to the target element
event.target.dispatchEvent(simulatedEvent);
@ -118,7 +125,7 @@
function fireMouseDown () {
const self = this;
var self = this;
delayFinished = true;
@ -145,7 +152,7 @@
*/
mouseProto._touchStart = function (event) {
let self = this;
var self = this;
// Interaction time
this._startedMove = event.timeStamp;
@ -217,23 +224,22 @@
// 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
let timeMoving = event.timeStamp - this._startedMove;
var timeMoving = event.timeStamp - this._startedMove;
if (!this._touchMoved || timeMoving < 500) {
// Simulate the dblclick event if last click was not far away from the previous one
if ( event.timeStamp - lastClickTime < 400 &&
// Simulate the click event
simulateMouseEvent(event, 'click');
if (lastClickTimeStamp != 0 && event.timeStamp - lastClickTimeStamp < 500 &&
Math.abs(lastClickCoord.x - this._startPos.x) < 10 && Math.abs(lastClickCoord.y - this._startPos.y) < 10) {
// Simulate the dblclick event
simulateMouseEvent(event, 'dblclick');
}
// Simulate the click event
else
simulateMouseEvent(event, 'click');
lastClickTime = event.timeStamp
lastClickTimeStamp = event.timeStamp
lastClickCoord = this._startPos;
}
else {
let endPos = getTouchCoords(event);
var 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') {
@ -250,10 +256,6 @@
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
@ -262,22 +264,18 @@
*/
mouseProto._mouseInit = function () {
let self = this;
// Microsoft Surface Support = remove original touch Action
if ($.mspointer) {
self.element[0].style.msTouchAction = 'none';
}
var self = this;
_touchStartBound = mouseProto._touchStart.bind(self);
_touchMoveBound = mouseProto._touchMove.bind(self);
_touchEndBound = mouseProto._touchEnd.bind(self);
// Microsoft Surface Support = remove original touch Action
if ($.support.mspointer) {
self.element[0].style.msTouchAction = 'none';
}
// Delegate the touch handlers to the widget's element
self.element.on({
touchstart: _touchStartBound,
touchmove: _touchMoveBound,
touchend: _touchEndBound
touchstart: $.proxy(self, '_touchStart'),
touchmove: $.proxy(self, '_touchMove'),
touchend: $.proxy(self, '_touchEnd')
});
// Call the original $.ui.mouse init method
@ -289,13 +287,13 @@
*/
mouseProto._mouseDestroy = function () {
let self = this;
var self = this;
// Delegate the touch handlers to the widget's element
self.element.off({
touchstart: _touchStartBound,
touchmove: _touchMoveBound,
touchend: _touchEndBound
touchstart: $.proxy(self, '_touchStart'),
touchmove: $.proxy(self, '_touchMove'),
touchend: $.proxy(self, '_touchEnd')
});
// 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-2025 Max Pozdeev <maxpozdeev@gmail.com>
(C) Copyright 2009-2010,2020-2023 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: false,
tagPreview: true,
tagPreviewDelay: 700, //milliseconds
ajaxAnimationDelay: 200,
saveShowNotes: false,
@ -78,15 +78,13 @@ var mytinytodo = window.mytinytodo = _mtt = {
history: true,
markdown: true,
viewTaskOnClick: false,
newTaskCounter: false,
newTaskCounterIcon: false,
newTaskCounter: true,
},
timers: {
previewtag: 0,
ajaxAnimation: 0,
newTaskCounter: 0,
searchTags: 0,
},
lang: {
@ -138,9 +136,7 @@ var mytinytodo = window.mytinytodo = _mtt = {
// procs
setApiDriver: function(driver)
{
this.db = new driver({
useREST: false
});
this.db = new driver(_mtt);
return this;
},
@ -293,42 +289,19 @@ 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();
document.getElementById('tagcloudSearch').value = '';
});
loadTags(curList.id, function(){$('#tagcloudload').hide();});
}
},
alignRight: true,
onClose: function(){
document.getElementById('tagcloudSearch').value = '';
searchTags();
}
alignRight:true
});
_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();
});
@ -336,8 +309,7 @@ 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;
});
@ -345,10 +317,7 @@ var mytinytodo = window.mytinytodo = _mtt = {
flag.showTagsFromAllLists = this.checked;
$('#tagcloudcontent').html('');
$('#tagcloudload').show();
loadTags(curList.id, function(){
$('#tagcloudload').hide();
$('#tagcloudSearch').val('');
});
loadTags(curList.id, function(){$('#tagcloudload').hide();});
});
$('#mtt-notes-show').click(function(e){
@ -443,8 +412,6 @@ 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()
});
@ -749,15 +716,11 @@ 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 /* TODO: && !flag.readOnly */) {
if (this.options.newTaskCounter) {
this.addAction('listsLoaded', newTaskCounterStart);
this.addAction('listSelected', newTaskCounterOnListSelected)
if (this.options.newTaskCounterIcon) {
this.addAction('newTaskCounterUpdated', newTaskCounterUpdated);
}
}
this.doAction( 'init' );
@ -902,19 +865,16 @@ var mytinytodo = window.mytinytodo = _mtt = {
duedatepickerformat: function()
{
if (!this.options.duedatepickerformat)
return 'yy-mm-dd';
if(!this.options.duedatepickerformat) return 'yy-mm-dd';
const s = this.options.duedatepickerformat.replace(/(.)/g, function(t,s) {
var 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;
@ -922,8 +882,7 @@ var mytinytodo = window.mytinytodo = _mtt = {
}
});
if (s == '')
return 'yy-mm-dd';
if(s == '') return 'yy-mm-dd';
return s;
},
@ -980,38 +939,25 @@ var mytinytodo = window.mytinytodo = _mtt = {
filter: {
_filters: [],
clear() {
clear: function() {
this._filters = [];
$('#mtt-tag-toolbar').hide();
$('#mtt-tag-filters').html('');
},
addTag(tagId, tag, exclude)
addTag: function(tagId, tag, exclude)
{
//Catch 'any tag' filter
if (tagId == -2) {
tagId = -1;
tag = '^';
exclude = true
}
for (const filter of this._filters) {
if (filter.tagId && filter.tagId == tagId)
tagId += 0;
for (let i in this._filters) {
if (this._filters[i].tagId && this._filters[i].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(tagId)
cancelTag: function(tagId)
{
for (let i in this._filters) {
if (this._filters[i].tagId && this._filters[i].tagId == tagId) {
@ -1025,25 +971,23 @@ var mytinytodo = window.mytinytodo = _mtt = {
}
return false;
},
getTags(withExcluded)
getTags: function(withExcluded)
{
let a = [];
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)
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)
}
}
return a.join(', ');
},
prepareTagHtml(tagId, tag, classes)
prepareTagHtml: function(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>';
}
},
@ -1233,8 +1177,7 @@ function loadTasks(opts)
changeTaskCnt(item, 1);
});
curList.lastTime = json.time;
setNewTaskCounterForList(curList.id, 0);
_mtt.doAction("newTaskCounterUpdated", curList.id);
$('#list_'+curList.id).find('.counter').text('').addClass('hidden');
if(opts.beforeShow && opts.beforeShow.call) {
opts.beforeShow();
}
@ -1281,9 +1224,9 @@ function prepareTaskBlocks(item)
'<div class="task-through">' +
preparePrio(item.prio,id) +
'<span class="task-title">' + prepareTaskTitleInlineHtml(item.title) + '</span> ' +
(curList.id == -1 ? prepareListNameInline(item) : '') +
(curList.id == -1 ? '<span class="task-listname">'+ tabLists.get(item.listId).name +'</span>' : '') +
'<span class="task-tags">' + prepareTagsStr(item) + '</span>' +
'<div class="task-date">' + prepareInlineDate(item) + '</div>' +
'<span class="task-date">' + prepareInlineDate(item) + '</span>' +
'</div>' +
'<div class="task-through-right">' + prepareDueDate(item) + "</div>" +
'</div>' +
@ -1304,22 +1247,14 @@ _mtt.prepareTaskBlocks = prepareTaskBlocks;
function prepareTaskTitleInlineHtml(s)
{
// Task title is already escaped on back-end
// Task title is already escaped on php 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 back-end
// Task note is already escaped on php back-end
return s;
};
_mtt.prepareTaskNoteInlineHtml = prepareTaskNoteInlineHtml;
@ -1424,9 +1359,9 @@ function changeTaskOrder(id)
return 0;
}
// sortByHand
if (curList.sort == 0 || curList.sort == 100) {
if (curList.sort == 0) {
taskOrder.sort( (a, b) => firstNonZero(
curList.sort,
0,
taskList[a].compl - taskList[b].compl,
taskList[a].ow - taskList[b].ow
))
@ -1533,13 +1468,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 && curList.sort != 100) changeTaskOrder(id);
if(curList.sort != 0) changeTaskOrder(id);
$t.effect("highlight", {color:_mtt.theme.editTaskFlashColor}, 'normal');
};
function setSort(v, init)
{
if (v < 0 || (v > 5 && v < 100) || v > 105) {
if (v < 0 || (v > 5 && v < 101) || v > 105) {
return;
}
curList.sort = v;
@ -1550,7 +1485,7 @@ function setSort(v, init)
function updateSortUI(v)
{
$('#listmenucontainer .sort-item').removeClass('mtt-item-checked').children('.mtt-sort-direction').text('');
if (v == 0 || v == 100) $('#sortByHand').addClass('mtt-item-checked').children('.mtt-sort-direction').text(v==0 ? '↓' : '↑');
if (v == 0) $('#sortByHand').addClass('mtt-item-checked');
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 ? '↓' : '↑');
@ -1559,7 +1494,7 @@ function updateSortUI(v)
else return;
curList.sort = v;
if ( (v == 0 || v == 100) && !flag.readOnly) $("#tasklist").sortable('enable');
if (v == 0 && !flag.readOnly) $("#tasklist").sortable('enable');
else $("#tasklist").sortable('disable');
};
@ -1676,12 +1611,9 @@ 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', {
'list': curList,
'prevList':prevList
});
mytinytodo.doAction('listSelected', tabLists.get(id));
}
const newTitle = dehtml(curList.name) + ' - ' + _mtt.options.title;
const newTitle = curList.name + ' - ' + _mtt.options.title;
const isFirstLoad = flag.firstLoad;
//replaceHistoryState( 'list', { list:id }, _mtt.urlForList(curList), newTitle );
updateHistoryState( { list:id }, _mtt.urlForList(curList), newTitle );
@ -1732,7 +1664,7 @@ function listMenuClick(el, menu)
case 'btnRssFeed': return true;
case 'btnShowCompleted': showCompletedToggle(); break;
case 'btnClearCompleted': clearCompleted(); break;
case 'sortByHand': setSort(curList.sort==0 ? 100 : 0); break;
case 'sortByHand': setSort(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;
@ -1849,7 +1781,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.id == -1 ? item.listName : curList.name);
$('#page_taskviewer .list .content').text(curList.name);
if (item.note == '') {
$('#page_taskviewer').addClass('no-note');
}
@ -1864,7 +1796,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) + ' - ' + dehtml(curList.name) + ' - ' + _mtt.options.title);
updateHistoryState({ task: item.id, list: item.listId }, '#task/'+item.id, dehtml(item.title) + ' - ' + curList.name + ' - ' + _mtt.options.title);
}
@ -1967,9 +1899,8 @@ 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 && curList.sort != 100) {
if (curList.sort != 0)
changeTaskOrder(item.id);
}
refreshTaskCnt();
_mtt.pageBack(); //back to list or viewer
if (_mtt.pages.current.page == 'taskviewer') {
@ -2032,29 +1963,20 @@ 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);
@ -2064,27 +1986,10 @@ 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)
@ -2141,7 +2046,6 @@ 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();
@ -2164,50 +2068,39 @@ function tasklistSortStart(event, ui)
function tasklistSortUpdated(event, ui)
{
if (!ui.item[0]) {
return;
}
const itemId = ui.item[0].id;
const n = $(this).sortable('toArray');
if(!ui.item[0]) return;
var itemId = ui.item[0].id;
var n = $(this).sortable('toArray');
// remove possible empty id's
for (let i = 0; i < sortOrder.length; i++) {
if (sortOrder[i] == '') {
sortOrder.splice(i,1); i--;
}
}
if (n.toString() == sortOrder.toString()) {
return;
for(var i=0; i<sortOrder.length; i++) {
if(sortOrder[i] == '') { sortOrder.splice(i,1); i--; }
}
if(n.toString() == sortOrder.toString()) return;
// make index: id=>position
const posBefore = {};
for (let j = 0; j < sortOrder.length; j++) {
posBefore[sortOrder[j]] = j;
var h0 = {}; //before
for(var j=0; j<sortOrder.length; j++) {
h0[sortOrder[j]] = j;
}
const posAfter = {};
for (let j = 0; j < n.length; j++) {
posAfter[n[j]] = j;
var h1 = {}; //after
for(var j=0; j<n.length; j++) {
h1[n[j]] = j;
taskOrder[j] = parseInt(n[j].split('_')[1]);
}
// prepare params
const o = [];
const newWeight = taskList[sortOrder[posAfter[itemId]].split('_')[1]].ow;
let diff;
for (const j in posBefore)
// prepare param
var o = [];
var diff;
var replaceOW = taskList[sortOrder[h1[itemId]].split('_')[1]].ow;
for(var j in h0)
{
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;
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;
}
}
@ -2510,9 +2403,7 @@ 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 && curList.sort != 100) {
changeTaskOrder(item.id);
}
if(curList.sort != 0) changeTaskOrder(item.id);
refreshTaskCnt();
$('#taskrow_'+item.id).effect("highlight", {color:_mtt.theme.editTaskFlashColor}, 'normal', function(){$(this).css('display','')});
}
@ -2554,9 +2445,8 @@ function cmenuOnListRenamed(list)
$('#cmenu_list\\:'+list.id).text(list.name);
};
function cmenuOnListSelected(a)
function cmenuOnListSelected(list)
{
const list = a.list;
$('#cmenulistscontainer li').removeClass('mtt-item-disabled');
$('#cmenu_list\\:'+list.id).addClass('mtt-item-disabled').removeClass('mtt-list-hidden');
};
@ -2574,9 +2464,8 @@ function cmenuOnListHidden(list)
};
function tabmenuOnListSelected(a)
function tabmenuOnListSelected(list)
{
const list = a.list;
if (list.published) {
$('#btnPublish').addClass('mtt-item-checked');
$('#btnRssFeed').removeClass('mtt-item-disabled');
@ -2686,18 +2575,16 @@ function escapeHtml(str) {
function slmenuOnListsLoaded()
{
if (_mtt.menus.selectlist) {
if(_mtt.menus.selectlist) {
_mtt.menus.selectlist.destroy();
_mtt.menus.selectlist = null;
}
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>`;
})
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>';
}
$('#slmenucontainer ul>.slmenu-lists-begin').nextAll().remove();
$('#slmenucontainer ul>.slmenu-lists-begin').after(s);
};
@ -2713,13 +2600,11 @@ 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><div class="counter hidden"></div></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></li>');
};
function slmenuOnListSelected(a)
function slmenuOnListSelected(list)
{
const list = a.list;
$('#slmenucontainer li').removeClass('mtt-item-checked');
$('#slmenucontainer li.list-id-'+list.id).addClass('mtt-item-checked').removeClass('mtt-list-hidden');
@ -2833,134 +2718,37 @@ function newTaskCounter()
});
});
_mtt.db.request("newTaskCounter", params, json => {
if (json && json.ok) {
let counters = {};
let curCounter = 0;
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) {
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) => {
counters["" + item.listId] = +item.counter;
$('#list_'+item.listId).find('.counter').text(item.counter).removeClass('hidden');
});
}
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
*/
@ -3169,17 +2957,8 @@ 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.alertTextOnLoad) {
mttAlert(json.alertTextOnLoad);
}
else if (json.msg) {
flashInfo(json.msg, json.details);
}
if (json.msg) flashInfo(json.msg, json.details);
if (json.reload) {
setTimeout( function(){
//window.location.hash = '';

View file

@ -1,72 +1,56 @@
/*
This file is a part of myTinyTodo.
(C) Copyright 2010,2020-2025 Max Pozdeev <maxpozdeev@gmail.com>
(C) Copyright 2010,2020,2022 Max Pozdeev <maxpozdeev@gmail.com>
Licensed under the GNU GPL version 2 or any later. See file COPYRIGHT for details.
*/
(function(){
"use strict";
/**
* @class
*/
function MytinytodoAjaxApi(props)
{
if (typeof mytinytodo !== 'object') {
throw "mytinytodo global object is not found!";
}
this.useREST = true;
var mtt;
if (props.hasOwnProperty('useREST')) {
this.useREST = !!props.useREST;
}
function MytinytodoAjaxApi(amtt)
{
mtt = amtt;
}
MytinytodoAjaxApi.prototype = {
window.MytinytodoAjaxApi = MytinytodoAjaxApi;
/**
* 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)
}
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)
});
},
loadTasks(params, callback) {
let q = '';
loadTasks: function(params, callback)
{
var 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(mytinytodo.apiUrl + 'tasks' + (mytinytodo.apiUrl.indexOf('?') > -1 ? '&' : '?') +
'list='+params.list+'&compl='+params.compl+'&sort='+params.sort+q,
callback);
$.getJSON(mtt.apiUrl + 'tasks' + (mtt.apiUrl.indexOf('?') > -1 ? '&' : '?') + 'list='+params.list+'&compl='+params.compl+'&sort='+params.sort+q, callback);
},
newTask(params, callback) {
newTask: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'tasks',
url: mtt.apiUrl + 'tasks',
method: 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'newSimple',
action: 'simple',
list: params.list,
title: params.title,
tag: params.tag,
@ -77,13 +61,14 @@ MytinytodoAjaxApi.prototype = {
},
fullNewTask(params, callback) {
fullNewTask: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'tasks',
url: mtt.apiUrl + 'tasks',
method: 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'newFull',
action: 'full',
list: params.list,
title: params.title,
note: params.note,
@ -98,10 +83,11 @@ MytinytodoAjaxApi.prototype = {
},
editTask(params, callback) {
editTask: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'edit',
@ -117,10 +103,11 @@ MytinytodoAjaxApi.prototype = {
},
editNote(params, callback) {
editNote: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'note',
@ -132,10 +119,11 @@ MytinytodoAjaxApi.prototype = {
},
completeTask(params, callback) {
completeTask: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'complete',
@ -147,24 +135,22 @@ MytinytodoAjaxApi.prototype = {
},
deleteTask(params, callback) {
deleteTask: function(params, callback)
{
$.ajax({
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',
}),
url: mtt.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: 'DELETE',
success: callback,
dataType: 'json'
});
},
setTaskPriority(params, callback) {
setTaskPriority: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'priority',
@ -175,10 +161,11 @@ MytinytodoAjaxApi.prototype = {
});
},
changeOrder(params, callback) {
changeOrder: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'tasks',
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'tasks',
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'order',
@ -189,18 +176,21 @@ MytinytodoAjaxApi.prototype = {
});
},
suggestTags(params, callback) {
$.getJSON(mytinytodo.apiUrl + 'suggestTags', {list:params.list, q:params.q}, callback);
suggestTags: function(params, callback)
{
$.getJSON(mtt.apiUrl + 'suggestTags', {list:params.list, q:params.q}, callback);
},
tagCloud(params, callback) {
$.getJSON(mytinytodo.apiUrl + 'tagCloud/' + encodeURIComponent(params.list), callback);
tagCloud: function(params, callback)
{
$.getJSON(mtt.apiUrl + 'tagCloud/' + encodeURIComponent(params.list), callback);
},
moveTask(params, callback) {
moveTask: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'tasks/' + encodeURIComponent(params.id),
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'move',
@ -212,9 +202,10 @@ MytinytodoAjaxApi.prototype = {
});
},
parseTaskStr(params, callback) {
parseTaskStr: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'tasks/parseTitle',
url: mtt.apiUrl + 'tasks/parseTitle',
method: 'POST',
contentType : 'application/json',
data: JSON.stringify({
@ -227,42 +218,20 @@ MytinytodoAjaxApi.prototype = {
});
},
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)
});
},
// Lists
loadLists(params, callback) {
$.getJSON(mytinytodo.apiUrl + 'lists', callback);
loadLists: function(params, callback)
{
$.getJSON(mtt.apiUrl + 'lists', callback);
},
addList(params, callback) {
addList: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'lists',
url: mtt.apiUrl + 'lists',
method: 'POST',
contentType : 'application/json',
data: JSON.stringify({
action: 'new',
name: params.name,
}),
success: callback,
@ -271,23 +240,21 @@ MytinytodoAjaxApi.prototype = {
},
deleteList(params, callback) {
deleteList: function(params, callback)
{
$.ajax({
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',
}),
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'DELETE',
success: callback,
dataType: 'json'
});
},
renameList(params, callback) {
renameList: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'rename',
@ -298,10 +265,11 @@ MytinytodoAjaxApi.prototype = {
});
},
setSort(params, callback) {
setSort: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'sort',
@ -313,10 +281,11 @@ MytinytodoAjaxApi.prototype = {
});
},
publishList(params, callback) {
publishList: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'publish',
@ -327,10 +296,11 @@ MytinytodoAjaxApi.prototype = {
});
},
enableFeedKey(params, callback) {
enableFeedKey: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'enableFeedKey',
@ -341,10 +311,11 @@ MytinytodoAjaxApi.prototype = {
});
},
setShowNotesInList(params, callback) {
setShowNotesInList: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'showNotes',
@ -355,10 +326,11 @@ MytinytodoAjaxApi.prototype = {
});
},
setHideList(params, callback) {
setHideList: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'hide',
@ -369,10 +341,11 @@ MytinytodoAjaxApi.prototype = {
});
},
changeListOrder(params, callback) {
changeListOrder: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'lists',
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'lists',
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'order',
@ -383,10 +356,11 @@ MytinytodoAjaxApi.prototype = {
});
},
clearCompletedInList(params, callback) {
clearCompletedInList: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: this.useREST ? 'PUT' : 'POST',
url: mtt.apiUrl + 'lists/' + encodeURIComponent(params.list),
method: 'PUT',
contentType : 'application/json',
data: JSON.stringify({
action: 'clearCompleted',
@ -398,9 +372,10 @@ MytinytodoAjaxApi.prototype = {
/* Auth */
login(params, callback) {
login: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'login',
url: mtt.apiUrl + 'login',
method: 'POST',
contentType : 'application/json',
data: JSON.stringify({
@ -411,9 +386,10 @@ MytinytodoAjaxApi.prototype = {
});
},
logout(params, callback) {
logout: function(params, callback)
{
$.ajax({
url: mytinytodo.apiUrl + 'logout',
url: mtt.apiUrl + 'logout',
method: 'POST',
success: callback,
dataType: 'json'
@ -421,3 +397,5 @@ MytinytodoAjaxApi.prototype = {
}
};
})();

View file

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

View file

@ -1,6 +1,7 @@
@media print {
html,body { height:auto; }
html { height:0; }
body { height:0; min-height:0; margin:0; }
h2 { display: none; }
h3 { border-bottom:2px solid #777777; }
#toolbar { display: none; }
@ -9,9 +10,8 @@
.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.mtt-tab-selected .title { text-align:left; padding:0; margin:0; max-width:none; font-size:1.3rem; color:#000; }
.mtt-tab a span { text-align:left; padding: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: 1rem;
margin-bottom:8px;
box-sizing: border-box;
}
@ -176,13 +176,7 @@ body::after {
content:url(images/logo-loading.gif);
}
h3.page-title {
margin:0;
border-bottom:2px solid var(--color-content-delimiter);
margin-bottom:1rem;
padding:0.6rem 0;
font-size:1.1rem;
}
h3.page-title { margin:0; border-bottom:2px solid var(--color-content-delimiter); margin-bottom:10px; 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; }
@ -606,15 +600,12 @@ 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;
@ -625,9 +616,6 @@ 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);
}
@ -661,15 +649,14 @@ li.task-row.task-expanded .task-toggle { transform:rotate(90deg); }
margin-top: 0.2rem;
display: none;
}
.task-id::after {
content: ' · '; /* '&middot;' */
.task-id {
/*display: none;*/
}
#mtt.show-date .task-date {
display: block;
}
#mtt.show-date.date-inline .task-date {
display: inline-block; /* for RTL */
margin:0;
display: inline;
margin-left:3px;
}
.task-through { overflow:hidden; flex-grow:1; }
@ -691,7 +678,7 @@ li.task-row.task-expanded .task-toggle { transform:rotate(90deg); }
}
.task-tags {
margin:0px 3px;
display: inline;
display: inline-block; /* for RTL */
}
.task-tags:empty {
margin:0;
@ -714,7 +701,6 @@ 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 {
@ -778,12 +764,13 @@ 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) }
@ -810,43 +797,23 @@ li.task-row.task-completed .task-note-block .task-note { text-decoration:line-th
text-align: center;
}
.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 { margin-top:0.6rem; }
.form-row .h {
font-weight:bold;
color: var(--color-text-reduced);
}
.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;
.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;
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; }
@ -869,8 +836,6 @@ textarea.form-input.inmax {
#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;
@ -911,9 +876,6 @@ textarea.form-input.inmax {
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; }
@ -978,9 +940,6 @@ textarea.form-input.inmax {
#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);
@ -1073,23 +1032,7 @@ textarea.form-input.inmax {
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;
@ -1163,15 +1106,6 @@ 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; }
@ -1205,19 +1139,14 @@ 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.75rem;
margin-top: 0.5rem;
margin-bottom: 0.5rem;
border-radius: 1rem;
background-color: var(--color-settings-row);
}
.mtt-settings-table .group .tr {
margin: 0 10px;
margin: 0 1rem;
padding: 1rem 0;
}
.mtt-settings-table .group .th {
@ -1233,12 +1162,8 @@ li.mtt-item-hidden { display:none; }
padding: 0 10px;
}
.mtt-settings-table .th {
width: 30%;
font-weight: bold;
font-weight: 600;
}
.mtt-settings-table .group-header .th {
font-size: 0.9rem;
width: 30%;
font-weight: bold;
}
.mtt-settings-table .td {
flex-grow: 1;
@ -1361,12 +1286,10 @@ li.mtt-item-hidden { display:none; }
font-size: 16px;
-webkit-text-size-adjust: 100%; /* Dont increase font-size in horizontal orientation on ios */
}
textarea.form-input.inmax { font-size: 14px; }
#page_taskedit .form-row textarea.in500 { font-size: 14px; }
}
/* ========== narrow screens =========*/
/* narrow screens */
@media only screen and (max-width: 600px) {
#mtt { padding: 15px 8px 0px; }
@ -1408,10 +1331,6 @@ 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;
@ -1439,13 +1358,11 @@ 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; opacity: 0.9; }
#tasklist .ui-sortable-helper .task-left { visibility: hidden }
#tasklist .ui-sortable-helper .task-actions > * { visibility: hidden }
#tasklist .ui-sortable-helper { box-shadow:0px 0px 3px #555; }
#page_taskedit { max-width:100%; border:none; position:static; padding:0; }
#page_taskedit .form-table { width:100%; }
#page_taskedit .form-row textarea { height: 150px; }
#page_taskedit .form-row textarea { height: 70px; }
#loading { padding:0px; padding-top:1px; padding-right:1px; height:16px; overflow:hidden; }
@ -1453,18 +1370,11 @@ 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.4rem;
padding-bottom: 0.4rem;
}
.mtt-menu-container li { padding-top:0.3rem; padding-bottom:0.3rem; }
#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;
@ -1477,8 +1387,7 @@ li.mtt-item-hidden { display:none; }
}
#page_taskviewer .note,
#page_taskviewer .no-note {
padding-bottom: 1rem;
margin-bottom: 1rem;
padding-bottom:10px;
border-bottom: 2px solid var(--color-tasklist-row-expanded-border);
}
@ -1489,22 +1398,15 @@ 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 1rem;
margin: 0 0;
padding: 1rem 0;
margin: 0 1rem;
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;
@ -1516,12 +1418,7 @@ 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;
box-sizing: border-box;
}
.mtt-settings-table input , .mtt-settings-table select, .mtt-settings-table label { margin-top:5px; background-color: var(--color-settings-row); }
.form-bottom-buttons > * {
padding: 7px;

View file

@ -1,23 +1,13 @@
body { direction:rtl; }
.topblock h2 {
background-position: right;
padding-left: 10px;
padding-right: 30px;
}
h2 { padding-left:10px; padding-right:0px; }
#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; transform:rotateY(180deg); }
#newtask_adv { margin-left:0; margin-right:0.5rem; }
.mtt-searchbox-icon.mtt-icon-search { right:4px; left:auto; }
.mtt-searchbox-icon.mtt-icon-cancelsearch { left:4px; right:auto; }
@ -37,9 +27,10 @@ body { direction:rtl; }
.duedate:before { content:'\20\2190\20'; }
#tagcloud { box-shadow:-1px 2px 5px rgba(0,0,0,0.5); }
#tagcloudcancel { float:left; }
h3.page-title a.mtt-back-button { transform:rotate(180deg); }
.form-row-short { margin-left:12px; margin-right:0; }
#taskedit-date { float:left; }
#page_taskedit .form-row-short { float:right; 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); }

View file

@ -1,5 +0,0 @@
<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-2025 Max Pozdeev <maxpozdeev@gmail.com>
(C) Copyright 2023 Max Pozdeev <maxpozdeev@gmail.com>
Licensed under the GNU GPL version 2 or any later. See file COPYRIGHT for details.
*/
@ -86,9 +86,11 @@ class Backup
}
$db = \DBConnection::instance();
$props = null;
$autoinc = $this->getTableAutoIncrement($table);
if ($autoinc != '') {
$props = ['auto_increment' => $autoinc];
if ($db::DBTYPE == \DBConnection::DBTYPE_MYSQL) {
$autoinc = $this->getMysqlTableAutoIncrement($table);
if ($autoinc != '') {
$props = ['auto_increment' => $autoinc];
}
}
$this->writeOpeningTag($group, $props);
$q = $db->dq("SELECT * FROM $table");
@ -118,26 +120,11 @@ class Backup
$this->writeClosingTag($entity);
}
function getTableAutoIncrement($table): string
function getMysqlTableAutoIncrement(string $table): string
{
$db = \DBConnection::instance();
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 '';
$r = $db->sqa("SHOW TABLE STATUS WHERE Name=?", [$table]);
return (string)$r['Auto_increment'] ?? '';
}

View file

@ -31,9 +31,8 @@ class Controller extends \ApiController
$this->response->data = [
'total' => 1,
'ok' => true,
'msg' => __("backup.done"),
'alertTextOnLoad' => __("backup.done"),
'details' => ''
];
}
@ -119,17 +118,12 @@ 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()
@ -147,9 +141,7 @@ 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-2025 Max Pozdeev <maxpozdeev@gmail.com>
(C) Copyright 2023 Max Pozdeev <maxpozdeev@gmail.com>
Licensed under the GNU GPL version 2 or any later. See file COPYRIGHT for details.
*/
@ -217,9 +217,6 @@ 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;
}
@ -235,9 +232,8 @@ class Restore
$db->ex("TRUNCATE TABLE $table RESTART IDENTITY");
}
else {
# - 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
// we do not use TRUNCATE on mysql due to autocommit
// sqlite has truncate optimizer
$db->ex("DELETE FROM $table");
}
}

View file

@ -1,6 +1,6 @@
{
"bundleId": "backup",
"name": "Backup",
"version": "1.1",
"version": "0.9",
"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:i:s", $time)) );
$lastBackup = htmlspecialchars( sprintf($e('backup.last_backup'), formatTime(Config::get('dateformat'). " H:m: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" data-ext="$ext"> {$e('backup.check')} </button> &nbsp;
<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:repairInconsistency" data-ext="$ext"> {$e('backup.repair')} </button> <br>
</div>
</div>

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') && function_exists('posix_setsid')) {
if ($useCli && function_exists('pcntl_fork')) {
$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_getpwuid') && false !== ($userinfo = posix_getpwuid(posix_getuid())) ) {
if (function_exists('posix_getuid') && 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-2023 Max Pozdeev <maxpozdeev@gmail.com>
(C) Copyright 2022 Max Pozdeev <maxpozdeev@gmail.com>
Licensed under the GNU GPL version 2 or any later. See file COPYRIGHT for details.
*/
@ -16,10 +16,6 @@ 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.2.1",
"version": "1.1",
"description": "Notify about new tasks and lists on e-mail or telegram"
}

View file

@ -1,30 +0,0 @@
{
"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,12 +3,11 @@
"notifications.urlconfigwarning": "Enable PHP 'allow_url_fopen' directive to use Telegram notifications.",
"notifications.check": "Check",
"notifications.bot_not_configured": "Bot is not configured",
"notifications.g_email": "E-Mail",
"notifications.h_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.g_telegram": "Telegram",
"notifications.h_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,12 +3,11 @@
"notifications.urlconfigwarning": "Для использования Telegram требуется включить директиву 'allow_url_fopen' в настройках PHP .",
"notifications.check": "Проверить",
"notifications.bot_not_configured": "Бот не настроен",
"notifications.g_email": "E-Mail",
"notifications.h_email": "E-mail:",
"notifications.h_email": "E-Mail:",
"notifications.d_email": "Разделите несколько адресов c помощью запятой.",
"notifications.h_mailfrom": "Адрес отправителя:",
"notifications.d_mailfrom": "Этот адрес будет указан как адрес отправителя в письмах с уведомлениями.",
"notifications.g_telegram": "Telegram",
"notifications.h_telegram": "Telegram",
"notifications.h_token": "Токен для бота:",
"notifications.d_token": "Токен для телеграм-бота, полученный от @BotFather.",
"notifications.h_active_chats": "Активные чаты:",

View file

@ -113,11 +113,6 @@ 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>
@ -130,12 +125,9 @@ $warning
</div>
<div class="td"> <input name="mailfrom" value="$mailfrom" class="in350" autocomplete="email" placeholder="$mailfromDefault"> </div>
</div>
</div><!--/group-->
<div class="tr group-header">
<div class="th"> {$e('notifications.g_telegram')} </div>
<div class="tr">
<div class="th"> {$e('notifications.h_telegram')} </div>
</div>
<div class="group">
<div class="tr">
<div class="th"> {$e('notifications.h_token')}
<div class="descr">{$e('notifications.d_token')}</div>
@ -154,7 +146,6 @@ $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