From 77380014bbab2ac0341a80942a81e597551bb7eb Mon Sep 17 00:00:00 2001 From: Gvx Date: Mon, 14 Nov 2022 20:54:31 +0100 Subject: [PATCH] Version 2.3.0 --- CHANGELOG.md | 82 +- README.md | 2 +- dcScript/CHANGELOG.md | 8 +- dcScript/_admin.php | 4 +- dcScript/_config.php | 4 +- dcScript/_define.php | 16 +- dcScript/_init.php | 24 + dcScript/_install.php | 4 +- dcScript/_prepend.php | 10 +- dcScript/_public.php | 4 +- dcScript/bin/build.bat | 86 ++ dcScript/bin/excludes.txt | 6 + dcScript/bin/phpStan.bat | 20 + dcScript/bin/phpstan.bootstrap.php | 42 + dcScript/bin/release.bat | 81 ++ dcScript/codemirror/addon/comment/comment.js | 8 +- .../addon/comment/continuecomment.js | 114 +++ dcScript/codemirror/addon/dialog/dialog.css | 32 + dcScript/codemirror/addon/dialog/dialog.js | 6 +- .../codemirror/addon/display/autorefresh.js | 47 + .../codemirror/addon/display/fullscreen.css | 6 + .../codemirror/addon/display/fullscreen.js | 2 +- dcScript/codemirror/addon/display/panel.js | 133 +++ .../codemirror/addon/display/placeholder.js | 78 ++ dcScript/codemirror/addon/display/rulers.js | 51 + .../codemirror/addon/edit/closebrackets.js | 201 ++++ dcScript/codemirror/addon/edit/closetag.js | 185 ++++ .../codemirror/addon/edit/continuelist.js | 101 ++ .../codemirror/addon/edit/matchbrackets.js | 30 +- dcScript/codemirror/addon/edit/matchtags.js | 2 +- .../codemirror/addon/edit/trailingspace.js | 2 +- dcScript/codemirror/addon/fold/brace-fold.js | 96 +- .../codemirror/addon/fold/comment-fold.js | 2 +- dcScript/codemirror/addon/fold/foldcode.js | 12 +- dcScript/codemirror/addon/fold/foldgutter.css | 20 + dcScript/codemirror/addon/fold/foldgutter.js | 8 +- dcScript/codemirror/addon/fold/indent-fold.js | 2 +- .../codemirror/addon/fold/markdown-fold.js | 49 + dcScript/codemirror/addon/fold/xml-fold.js | 2 +- .../codemirror/addon/search/jump-to-line.js | 53 ++ .../addon/search/match-highlighter.js | 167 ++++ .../addon/search/matchesonscrollbar.css | 8 + .../addon/search/matchesonscrollbar.js | 97 ++ dcScript/codemirror/addon/search/search.js | 53 +- .../codemirror/addon/search/searchcursor.js | 33 +- .../codemirror/addon/selection/active-line.js | 2 +- .../addon/selection/mark-selection.js | 119 +++ .../addon/selection/selection-pointer.js | 98 ++ dcScript/codemirror/lib/codemirror.css | 33 +- dcScript/codemirror/lib/codemirror.js | 889 ++++++++++-------- dcScript/codemirror/mode/css/css.js | 281 +++--- dcScript/codemirror/mode/css/gss.html | 104 ++ dcScript/codemirror/mode/css/gss_test.js | 17 + dcScript/codemirror/mode/css/index.html | 81 ++ dcScript/codemirror/mode/css/less.html | 152 +++ dcScript/codemirror/mode/css/less_test.js | 54 ++ dcScript/codemirror/mode/css/scss.html | 158 ++++ dcScript/codemirror/mode/css/scss_test.js | 110 +++ dcScript/codemirror/mode/css/test.js | 217 +++++ .../codemirror/mode/htmlmixed/htmlmixed.js | 7 +- dcScript/codemirror/mode/htmlmixed/index.html | 100 ++ .../codemirror/mode/javascript/index.html | 118 +++ .../codemirror/mode/javascript/javascript.js | 78 +- .../codemirror/mode/javascript/json-ld.html | 72 ++ dcScript/codemirror/mode/javascript/test.js | 521 ++++++++++ .../mode/javascript/typescript.html | 62 ++ dcScript/codemirror/mode/xml/index.html | 61 ++ dcScript/codemirror/mode/xml/test.js | 51 + dcScript/codemirror/mode/xml/xml.js | 24 +- dcScript/dcstore.xml | 13 + .../class.dcPluginHelper224.php} | 285 +++--- dcScript/inc/class.dcScript.php | 217 ++--- dcScript/inc/css/index.css | 4 +- dcScript/inc/js/index.js | 4 +- dcScript/inc/js/index_warning.js | 4 +- dcScript/index.php | 4 +- dcScript/locales/en/resources.php | 4 +- dcScript/locales/fr/resources.php | 4 +- dcScript/phpstan.neon | 132 +++ dcScript/tools/decrypt.php | 2 +- dcstore.xml | 13 + 81 files changed, 5049 insertions(+), 1039 deletions(-) create mode 100644 dcScript/_init.php create mode 100644 dcScript/bin/build.bat create mode 100644 dcScript/bin/excludes.txt create mode 100644 dcScript/bin/phpStan.bat create mode 100644 dcScript/bin/phpstan.bootstrap.php create mode 100644 dcScript/bin/release.bat create mode 100644 dcScript/codemirror/addon/comment/continuecomment.js create mode 100644 dcScript/codemirror/addon/dialog/dialog.css create mode 100644 dcScript/codemirror/addon/display/autorefresh.js create mode 100644 dcScript/codemirror/addon/display/fullscreen.css create mode 100644 dcScript/codemirror/addon/display/panel.js create mode 100644 dcScript/codemirror/addon/display/placeholder.js create mode 100644 dcScript/codemirror/addon/display/rulers.js create mode 100644 dcScript/codemirror/addon/edit/closebrackets.js create mode 100644 dcScript/codemirror/addon/edit/closetag.js create mode 100644 dcScript/codemirror/addon/edit/continuelist.js create mode 100644 dcScript/codemirror/addon/fold/foldgutter.css create mode 100644 dcScript/codemirror/addon/fold/markdown-fold.js create mode 100644 dcScript/codemirror/addon/search/jump-to-line.js create mode 100644 dcScript/codemirror/addon/search/match-highlighter.js create mode 100644 dcScript/codemirror/addon/search/matchesonscrollbar.css create mode 100644 dcScript/codemirror/addon/search/matchesonscrollbar.js create mode 100644 dcScript/codemirror/addon/selection/mark-selection.js create mode 100644 dcScript/codemirror/addon/selection/selection-pointer.js create mode 100644 dcScript/codemirror/mode/css/gss.html create mode 100644 dcScript/codemirror/mode/css/gss_test.js create mode 100644 dcScript/codemirror/mode/css/index.html create mode 100644 dcScript/codemirror/mode/css/less.html create mode 100644 dcScript/codemirror/mode/css/less_test.js create mode 100644 dcScript/codemirror/mode/css/scss.html create mode 100644 dcScript/codemirror/mode/css/scss_test.js create mode 100644 dcScript/codemirror/mode/css/test.js create mode 100644 dcScript/codemirror/mode/htmlmixed/index.html create mode 100644 dcScript/codemirror/mode/javascript/index.html create mode 100644 dcScript/codemirror/mode/javascript/json-ld.html create mode 100644 dcScript/codemirror/mode/javascript/test.js create mode 100644 dcScript/codemirror/mode/javascript/typescript.html create mode 100644 dcScript/codemirror/mode/xml/index.html create mode 100644 dcScript/codemirror/mode/xml/test.js create mode 100644 dcScript/dcstore.xml rename dcScript/inc/{class.dcPluginHelper.php => _dcPluginHelper/class.dcPluginHelper224.php} (64%) create mode 100644 dcScript/phpstan.neon create mode 100644 dcstore.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 34f0667..ab1d201 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,40 +1,42 @@ -Changelog -========= - -Version 2.2.0 (2020-04-xx) --------------------------- - -* Correctifs divers -* Mise a niveau dcPluginHelper 216 -* Version mini dc 2.16 - -Version 2.1.2 (2020-04-07) --------------------------- - -* Correctif insertion cote public -* Correctif sauvegarde settings - -Version 2.1.1 (2020-04-04) --------------------------- - -* Correctif algorithme de cryptage - -Version 2.1.0 (2020-03-30) --------------------------- - -* Suppression de la dépendance a jQuery -* Passage a la version 5.52.0 de CodeMirror -* Changement de système de cryptage compatible PHP 7.2 -* Mise a jour support -* Correction procédure désinstallation -* Corrections divers - -Version 2.0.1 (2016-03-05) --------------------------- - -* Correctif insertion cote public - -Version 2.0.0 (2015-10-16) --------------------------- - -* Première release publique +Changelog +========= + +Version 2.3.0 (2022-11-14) +-------------------------- + +* Mise a niveau dcPluginHelper pour dc 2.24 +* Version mini dc 2.24 +* Ajout d'un depot alternatif +* Passage a la version 5.65.9 de CodeMirror +* Correctifs divers + +Version 2.1.2 (2020-04-07) +-------------------------- + +* Correctif insertion cote public +* Correctif sauvegarde settings + +Version 2.1.1 (2020-04-04) +-------------------------- + +* Correctif algorithme de cryptage + +Version 2.1.0 (2020-03-30) +-------------------------- + +* Suppression de la dépendance a jQuery +* Passage a la version 5.52.0 de CodeMirror +* Changement de système de cryptage compatible PHP 7.2 +* Mise a jour support +* Correction procédure désinstallation +* Corrections divers + +Version 2.0.1 (2016-03-05) +-------------------------- + +* Correctif insertion cote public + +Version 2.0.0 (2015-10-16) +-------------------------- + +* Première release publique diff --git a/README.md b/README.md index d79973d..4e53ae0 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ L'éditeur de code utilise la coloration syntaxique de [CodeMirror](https://code ## Pré-requis ## -* Dotclear 2.8 ou plus +* Dotclear 2.24 ou plus ## Utilisation ## diff --git a/dcScript/CHANGELOG.md b/dcScript/CHANGELOG.md index 0485c4a..ab1d201 100644 --- a/dcScript/CHANGELOG.md +++ b/dcScript/CHANGELOG.md @@ -1,12 +1,14 @@ Changelog ========= -Version 2.2.0 (2020-05-xx) +Version 2.3.0 (2022-11-14) -------------------------- +* Mise a niveau dcPluginHelper pour dc 2.24 +* Version mini dc 2.24 +* Ajout d'un depot alternatif +* Passage a la version 5.65.9 de CodeMirror * Correctifs divers -* Mise a niveau dcPluginHelper 216 -* Version mini dc 2.16 Version 2.1.2 (2020-04-07) -------------------------- diff --git a/dcScript/_admin.php b/dcScript/_admin.php index 4c932bb..723e60f 100644 --- a/dcScript/_admin.php +++ b/dcScript/_admin.php @@ -5,10 +5,10 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2022 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ if(!defined('DC_CONTEXT_ADMIN')) { return; } -$core->dcScript->_admin(); +dcCore::app()->dcScript->_admin(); diff --git a/dcScript/_config.php b/dcScript/_config.php index 4592e1d..bc518fb 100644 --- a/dcScript/_config.php +++ b/dcScript/_config.php @@ -5,10 +5,10 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2022 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ if(!defined('DC_CONTEXT_ADMIN')) { return; } -$core->dcScript->_config(); +dcCore::app()->dcScript->_config(); diff --git a/dcScript/_define.php b/dcScript/_define.php index 93dbeaa..c1913d3 100644 --- a/dcScript/_define.php +++ b/dcScript/_define.php @@ -5,7 +5,7 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2022 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ @@ -15,17 +15,23 @@ /* Name */ 'dcScript', /* Description*/ 'Add script for DC', /* Author */ 'Gvx', - /* Version */ '2.2.0-dev-r0015', + /* Version */ '2.3.0', array( /* standard plugin options dotclear */ - 'permissions' => 'dcScript.edit', + 'permissions' => dcCore::app()->auth->makePermissions([dcScriptPerms::EDIT]), 'type' => 'plugin', 'Priority' => 1010, 'support' /* url */ => 'http://forum.dotclear.org/viewtopic.php?pid=335785#p335785', 'details' /* url */ => 'https://github.com/Gvx-/dcScript', 'requires' /* id(s) */ => array( - array('core', '2.16') + array('core', '2.24') ), + 'settings' => array( + //'self' => '', // Optionnal: '#onglet' (or false since 2.17) + //'blog' => '#params.id', // Optionnal: '#params.id' + //'pref' => '#user-options.id', // Optionnal: '#user-options.id' + ), + 'repository' => 'https://raw.githubusercontent.com/Gvx-/dcScript/master/dcstore.xml', // Optionnal: URL /* specific plugin options */ '_class_name' => 'dcScript', // Required: plugin master class name '_class_path' => '/inc/class.dcScript.php', // Required: plugin master class path (relative) @@ -35,6 +41,6 @@ ); # --------------------------------------------------------- -# use codemirror version 5.52.0 +# use codemirror version 5.65.9 # see: http://codemirror.net/ # --------------------------------------------------------- diff --git a/dcScript/_init.php b/dcScript/_init.php new file mode 100644 index 0000000..4a2a3c6 --- /dev/null +++ b/dcScript/_init.php @@ -0,0 +1,24 @@ + + * @copyright © 2014-2022 Gvx + * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + */ + +if(!defined('DC_RC_PATH')) { return; } + + +class dcScriptPerms { + // Constants + + /** + * dcScript permission + * + * @var string + */ + public const EDIT = 'dcScript.edit'; +} diff --git a/dcScript/_install.php b/dcScript/_install.php index 259f67d..122dcf8 100644 --- a/dcScript/_install.php +++ b/dcScript/_install.php @@ -5,10 +5,10 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2022 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ if(!defined('DC_CONTEXT_ADMIN')) { return; } -return $core->dcScript->_install(); +return dcCore::app()->dcScript->_install(); diff --git a/dcScript/_prepend.php b/dcScript/_prepend.php index 076e223..0cadcb7 100644 --- a/dcScript/_prepend.php +++ b/dcScript/_prepend.php @@ -5,18 +5,18 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2022 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ if(!defined('DC_RC_PATH')) { return; } # define id and class specific plugin -$pluginId = basename(dirname(__FILE__)); -$pluginClassName = $core->plugins->moduleInfo($pluginId, '_class_name'); +$pluginId = basename(__DIR__); +$pluginClassName = dcCore::app()->plugins->moduleInfo($pluginId, '_class_name'); # Loadings & initialization if(!empty($pluginClassName)) { - $__autoload[$pluginClassName] = dirname(__FILE__).$core->plugins->moduleInfo($pluginId, '_class_path'); - $core->{$pluginClassName} = new $pluginClassName($core, $pluginId); + Clearbricks::lib()->autoload([$pluginClassName => __DIR__.dcCore::app()->plugins->moduleInfo($pluginId, '_class_path')]); + dcCore::app()->{$pluginClassName} = new $pluginClassName($pluginId); } diff --git a/dcScript/_public.php b/dcScript/_public.php index 8512d96..67c447b 100644 --- a/dcScript/_public.php +++ b/dcScript/_public.php @@ -5,10 +5,10 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2022 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ if(!defined('DC_RC_PATH')) { return; } -$core->dcScript->_public(); +dcCore::app()->dcScript->_public(); diff --git a/dcScript/bin/build.bat b/dcScript/bin/build.bat new file mode 100644 index 0000000..ea58cf9 --- /dev/null +++ b/dcScript/bin/build.bat @@ -0,0 +1,86 @@ +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: Build plugin dotclear +:: Author : Gilles Grandveaux +:: Copyright: (c)2020 Gilles Grandveaux +:: License : http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: Changelog +:: +:: * 08/11/2022 V0.1.3.0 +:: Changement de structure copie d'un dossier +:: * 18/04/2020 V0.1.2.3 +:: Correction exit sur message d'erreur et help +:: Correction protection des noms de fichiers +:: * 15/04/2020 V0.1.1.2 +:: Correction check paramettres +:: * 15/04/2020 V0.1.0.1 +:: version initiale +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +@echo off + +setlocal enabledelayedexpansion +:: Version script +set VERSION=0.1.2.3 + +if /I "%~1"=="-h" goto :help +if /I "%~1"=="--help" goto :help +if /I "%~1"=="-v" echo %VERSION% & exit /b +if /I "%~1"=="--version" echo %VERSION% & exit /b +if NOT [%1]==[] goto :help + +:: TODO: initialiser et +::set source=%~dp0..\..\dcHelper\inc\class.dcPluginHelper.php +::set dest=%~dp0..\inc\class.dcPluginHelper.php + +set source=%~dp0..\..\dcHelper\inc\_dcPluginHelper\*.* +set dest=%~dp0..\inc\_dcPluginHelper\ + + +call :parsePath f %source% source +call :parsePath f %dest% dest + +if not exist %source% call :fileError %source% +::if not exist %dest% call :fileError %dest% + +::copy /y "%source%" "%dest%" >NUL +xcopy "%source%" "%dest%" /Q /I /T /E /Y >NUL + +endlocal +exit /b + +:help +echo --== HELP ==-- +echo. +echo Usage: %~n0 [^<-v^>^|^<--version^>^|^<-h^>^|^<--help^>] +echo. +echo ^<-v^>^|^<--version^> : Display version +echo ^<-h^>^|^<--help^> : Display help +echo. +echo --== HELP ==-- +pause +exit /b 1 + +:fileError +echo --== ERREUR ==-- +echo. +echo le fichier "%~1" n'a pas ete trouve. +echo. +echo --== ERREUR ==-- +pause +exit 2 + +:parsePath +set %3=%~f2 +if /I "%~1"=="d" set %3=%~d2 +if /I "%~1"=="p" set %3=%~p2 +if /I "%~1"=="n" set %3=%~n2 +if /I "%~1"=="x" set %3=%~x2 +if /I "%~1"=="f" set %3=%~f2 +if /I "%~1"=="s" set %3=%~s2 +if /I "%~1"=="a" set %3=%~a2 +if /I "%~1"=="t" set %3=%~t2 +if /I "%~1"=="z" set %3=%~z2 +if /I "%~1"=="dp" set %3=%~dp2 +if /I "%~1"=="nx" set %3=%~nx2 +if /I "%~1"=="pathSearch" set %3=%~$PATH:2 rem search in PATH +goto:eof diff --git a/dcScript/bin/excludes.txt b/dcScript/bin/excludes.txt new file mode 100644 index 0000000..104f2d3 --- /dev/null +++ b/dcScript/bin/excludes.txt @@ -0,0 +1,6 @@ +\build-tools\ +.git +.vscode +.debug.php +*.bck.zip + diff --git a/dcScript/bin/phpStan.bat b/dcScript/bin/phpStan.bat new file mode 100644 index 0000000..b513ebb --- /dev/null +++ b/dcScript/bin/phpStan.bat @@ -0,0 +1,20 @@ +@echo off +set errorCode=0 + +set project=%~dp0..\phpStan.neon +if not exist %project% goto :error +echo phpStan analyse en cours... +php %userprofile%\vendor\phpstan\phpstan\phpstan analyse -c "%project%" +goto :endBatch + +:error +echo. +echo /!\ -- Le fichier %project% n'a pas ete trouve. +echo. +set errorCode=1 + +:: https://askcodez.com/conditionnel-pause-pas-en-ligne-de-commande.html +:endBatch +echo.%cmdcmdline% | find /I "%~0" >nul +if not errorlevel 1 pause +exit /b %errorCode% diff --git a/dcScript/bin/phpstan.bootstrap.php b/dcScript/bin/phpstan.bootstrap.php new file mode 100644 index 0000000..ded5a44 --- /dev/null +++ b/dcScript/bin/phpstan.bootstrap.php @@ -0,0 +1,42 @@ + et +set source=%~dp0.. +call :parsePath nx %source% plugin +set dest=%USERPROFILE%\Documents\__mesDocs\Git\%plugin%\%plugin%\ + +call :parsePath f %source% source +call :parsePath f %dest% dest + +if not exist %source% call :fileError %source% +if not exist %dest% call :fileError %dest% + +del /f /s /q "%dest%" >NUL +xcopy "%source%" "%dest%" /q /s /e /y /exclude:.\excludes.txt + +endlocal +exit /b + +:help +echo --== HELP ==-- +echo. +echo Usage: %~n0 [^<-v^>^|^<--version^>^|^<-h^>^|^<--help^>] +echo. +echo ^<-v^>^|^<--version^> : Display version +echo ^<-h^>^|^<--help^> : Display help +echo. +echo --== HELP ==-- +pause +exit /b 1 + +:fileError +echo --== ERREUR ==-- +echo. +echo le fichier "%~1" n'a pas ete trouve. +echo. +echo --== ERREUR ==-- +pause +exit 2 + +:parsePath +set %3=%~f2 +if /I "%~1"=="d" set %3=%~d2 +if /I "%~1"=="p" set %3=%~p2 +if /I "%~1"=="n" set %3=%~n2 +if /I "%~1"=="x" set %3=%~x2 +if /I "%~1"=="f" set %3=%~f2 +if /I "%~1"=="s" set %3=%~s2 +if /I "%~1"=="a" set %3=%~a2 +if /I "%~1"=="t" set %3=%~t2 +if /I "%~1"=="z" set %3=%~z2 +if /I "%~1"=="dp" set %3=%~dp2 +if /I "%~1"=="nx" set %3=%~nx2 +if /I "%~1"=="pathSearch" set %3=%~$PATH:2 rem search in PATH +goto:eof diff --git a/dcScript/codemirror/addon/comment/comment.js b/dcScript/codemirror/addon/comment/comment.js index 8394e85..7f6f3ed 100644 --- a/dcScript/codemirror/addon/comment/comment.js +++ b/dcScript/codemirror/addon/comment/comment.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -13,7 +13,7 @@ var noOptions = {}; var nonWS = /[^\s\u00a0]/; - var Pos = CodeMirror.Pos; + var Pos = CodeMirror.Pos, cmp = CodeMirror.cmpPos; function firstNonWS(str) { var found = str.search(nonWS); @@ -78,7 +78,7 @@ var baseString = null; for (var i = from.line; i < end; ++i) { var line = self.getLine(i); - var whitespace = line.slice(0, firstNonWS(line)); + var whitespace = line.search(nonWS) === -1 ? line : line.slice(0, firstNonWS(line)); if (baseString == null || baseString.length > whitespace.length) { baseString = whitespace; } @@ -126,7 +126,9 @@ if (i != end || lastLineHasText) self.replaceRange(lead + pad, Pos(i, 0)); } else { + var atCursor = cmp(self.getCursor("to"), to) == 0, empty = !self.somethingSelected() self.replaceRange(endString, to); + if (atCursor) self.setSelection(empty ? to : self.getCursor("from"), to) self.replaceRange(startString, from); } }); diff --git a/dcScript/codemirror/addon/comment/continuecomment.js b/dcScript/codemirror/addon/comment/continuecomment.js new file mode 100644 index 0000000..2f16da8 --- /dev/null +++ b/dcScript/codemirror/addon/comment/continuecomment.js @@ -0,0 +1,114 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var nonspace = /\S/g; + var repeat = String.prototype.repeat || function (n) { return Array(n + 1).join(this); }; + function continueComment(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), mode, inserts = []; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].head + if (!/\bcomment\b/.test(cm.getTokenTypeAt(pos))) return CodeMirror.Pass; + var modeHere = cm.getModeAt(pos) + if (!mode) mode = modeHere; + else if (mode != modeHere) return CodeMirror.Pass; + + var insert = null, line, found; + var blockStart = mode.blockCommentStart, lineCmt = mode.lineComment; + if (blockStart && mode.blockCommentContinue) { + line = cm.getLine(pos.line); + var end = line.lastIndexOf(mode.blockCommentEnd, pos.ch - mode.blockCommentEnd.length); + // 1. if this block comment ended + // 2. if this is actually inside a line comment + if (end != -1 && end == pos.ch - mode.blockCommentEnd.length || + lineCmt && (found = line.lastIndexOf(lineCmt, pos.ch - 1)) > -1 && + /\bcomment\b/.test(cm.getTokenTypeAt({line: pos.line, ch: found + 1}))) { + // ...then don't continue it + } else if (pos.ch >= blockStart.length && + (found = line.lastIndexOf(blockStart, pos.ch - blockStart.length)) > -1 && + found > end) { + // reuse the existing leading spaces/tabs/mixed + // or build the correct indent using CM's tab/indent options + if (nonspaceAfter(0, line) >= found) { + insert = line.slice(0, found); + } else { + var tabSize = cm.options.tabSize, numTabs; + found = CodeMirror.countColumn(line, found, tabSize); + insert = !cm.options.indentWithTabs ? repeat.call(" ", found) : + repeat.call("\t", (numTabs = Math.floor(found / tabSize))) + + repeat.call(" ", found - tabSize * numTabs); + } + } else if ((found = line.indexOf(mode.blockCommentContinue)) > -1 && + found <= pos.ch && + found <= nonspaceAfter(0, line)) { + insert = line.slice(0, found); + } + if (insert != null) insert += mode.blockCommentContinue + } + if (insert == null && lineCmt && continueLineCommentEnabled(cm)) { + if (line == null) line = cm.getLine(pos.line); + found = line.indexOf(lineCmt); + // cursor at pos 0, line comment also at pos 0 => shift it down, don't continue + if (!pos.ch && !found) insert = ""; + // continue only if the line starts with an optional space + line comment + else if (found > -1 && nonspaceAfter(0, line) >= found) { + // don't continue if there's only space(s) after cursor or the end of the line + insert = nonspaceAfter(pos.ch, line) > -1; + // but always continue if the next line starts with a line comment too + if (!insert) { + var next = cm.getLine(pos.line + 1) || '', + nextFound = next.indexOf(lineCmt); + insert = nextFound > -1 && nonspaceAfter(0, next) >= nextFound || null; + } + if (insert) { + insert = line.slice(0, found) + lineCmt + + line.slice(found + lineCmt.length).match(/^\s*/)[0]; + } + } + } + if (insert == null) return CodeMirror.Pass; + inserts[i] = "\n" + insert; + } + + cm.operation(function() { + for (var i = ranges.length - 1; i >= 0; i--) + cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert"); + }); + } + + function nonspaceAfter(ch, str) { + nonspace.lastIndex = ch; + var m = nonspace.exec(str); + return m ? m.index : -1; + } + + function continueLineCommentEnabled(cm) { + var opt = cm.getOption("continueComments"); + if (opt && typeof opt == "object") + return opt.continueLineComment !== false; + return true; + } + + CodeMirror.defineOption("continueComments", null, function(cm, val, prev) { + if (prev && prev != CodeMirror.Init) + cm.removeKeyMap("continueComment"); + if (val) { + var key = "Enter"; + if (typeof val == "string") + key = val; + else if (typeof val == "object" && val.key) + key = val.key; + var map = {name: "continueComment"}; + map[key] = continueComment; + cm.addKeyMap(map); + } + }); +}); diff --git a/dcScript/codemirror/addon/dialog/dialog.css b/dcScript/codemirror/addon/dialog/dialog.css new file mode 100644 index 0000000..677c078 --- /dev/null +++ b/dcScript/codemirror/addon/dialog/dialog.css @@ -0,0 +1,32 @@ +.CodeMirror-dialog { + position: absolute; + left: 0; right: 0; + background: inherit; + z-index: 15; + padding: .1em .8em; + overflow: hidden; + color: inherit; +} + +.CodeMirror-dialog-top { + border-bottom: 1px solid #eee; + top: 0; +} + +.CodeMirror-dialog-bottom { + border-top: 1px solid #eee; + bottom: 0; +} + +.CodeMirror-dialog input { + border: none; + outline: none; + background: transparent; + width: 20em; + color: inherit; + font-family: monospace; +} + +.CodeMirror-dialog button { + font-size: 70%; +} diff --git a/dcScript/codemirror/addon/dialog/dialog.js b/dcScript/codemirror/addon/dialog/dialog.js index 23b06a8..0294d23 100644 --- a/dcScript/codemirror/addon/dialog/dialog.js +++ b/dcScript/codemirror/addon/dialog/dialog.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Open simple dialogs on top of an editor. Relies on dialog.css. @@ -82,7 +82,9 @@ if (e.keyCode == 13) callback(inp.value, e); }); - if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close); + if (options.closeOnBlur !== false) CodeMirror.on(dialog, "focusout", function (evt) { + if (evt.relatedTarget !== null) close(); + }); } else if (button = dialog.getElementsByTagName("button")[0]) { CodeMirror.on(button, "click", function() { close(); diff --git a/dcScript/codemirror/addon/display/autorefresh.js b/dcScript/codemirror/addon/display/autorefresh.js new file mode 100644 index 0000000..b5e6ab0 --- /dev/null +++ b/dcScript/codemirror/addon/display/autorefresh.js @@ -0,0 +1,47 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")) + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod) + else // Plain browser env + mod(CodeMirror) +})(function(CodeMirror) { + "use strict" + + CodeMirror.defineOption("autoRefresh", false, function(cm, val) { + if (cm.state.autoRefresh) { + stopListening(cm, cm.state.autoRefresh) + cm.state.autoRefresh = null + } + if (val && cm.display.wrapper.offsetHeight == 0) + startListening(cm, cm.state.autoRefresh = {delay: val.delay || 250}) + }) + + function startListening(cm, state) { + function check() { + if (cm.display.wrapper.offsetHeight) { + stopListening(cm, state) + if (cm.display.lastWrapHeight != cm.display.wrapper.clientHeight) + cm.refresh() + } else { + state.timeout = setTimeout(check, state.delay) + } + } + state.timeout = setTimeout(check, state.delay) + state.hurry = function() { + clearTimeout(state.timeout) + state.timeout = setTimeout(check, 50) + } + CodeMirror.on(window, "mouseup", state.hurry) + CodeMirror.on(window, "keyup", state.hurry) + } + + function stopListening(_cm, state) { + clearTimeout(state.timeout) + CodeMirror.off(window, "mouseup", state.hurry) + CodeMirror.off(window, "keyup", state.hurry) + } +}); diff --git a/dcScript/codemirror/addon/display/fullscreen.css b/dcScript/codemirror/addon/display/fullscreen.css new file mode 100644 index 0000000..437acd8 --- /dev/null +++ b/dcScript/codemirror/addon/display/fullscreen.css @@ -0,0 +1,6 @@ +.CodeMirror-fullscreen { + position: fixed; + top: 0; left: 0; right: 0; bottom: 0; + height: auto; + z-index: 9; +} diff --git a/dcScript/codemirror/addon/display/fullscreen.js b/dcScript/codemirror/addon/display/fullscreen.js index eda7300..39451bd 100644 --- a/dcScript/codemirror/addon/display/fullscreen.js +++ b/dcScript/codemirror/addon/display/fullscreen.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/dcScript/codemirror/addon/display/panel.js b/dcScript/codemirror/addon/display/panel.js new file mode 100644 index 0000000..b00d683 --- /dev/null +++ b/dcScript/codemirror/addon/display/panel.js @@ -0,0 +1,133 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function (mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function (CodeMirror) { + CodeMirror.defineExtension("addPanel", function (node, options) { + options = options || {}; + + if (!this.state.panels) initPanels(this); + + var info = this.state.panels; + var wrapper = info.wrapper; + var cmWrapper = this.getWrapperElement(); + var replace = options.replace instanceof Panel && !options.replace.cleared; + + if (options.after instanceof Panel && !options.after.cleared) { + wrapper.insertBefore(node, options.before.node.nextSibling); + } else if (options.before instanceof Panel && !options.before.cleared) { + wrapper.insertBefore(node, options.before.node); + } else if (replace) { + wrapper.insertBefore(node, options.replace.node); + options.replace.clear(true); + } else if (options.position == "bottom") { + wrapper.appendChild(node); + } else if (options.position == "before-bottom") { + wrapper.insertBefore(node, cmWrapper.nextSibling); + } else if (options.position == "after-top") { + wrapper.insertBefore(node, cmWrapper); + } else { + wrapper.insertBefore(node, wrapper.firstChild); + } + + var height = (options && options.height) || node.offsetHeight; + + var panel = new Panel(this, node, options, height); + info.panels.push(panel); + + this.setSize(); + if (options.stable && isAtTop(this, node)) + this.scrollTo(null, this.getScrollInfo().top + height); + + return panel; + }); + + function Panel(cm, node, options, height) { + this.cm = cm; + this.node = node; + this.options = options; + this.height = height; + this.cleared = false; + } + + /* when skipRemove is true, clear() was called from addPanel(). + * Thus removePanels() should not be called (issue 5518) */ + Panel.prototype.clear = function (skipRemove) { + if (this.cleared) return; + this.cleared = true; + var info = this.cm.state.panels; + info.panels.splice(info.panels.indexOf(this), 1); + this.cm.setSize(); + if (this.options.stable && isAtTop(this.cm, this.node)) + this.cm.scrollTo(null, this.cm.getScrollInfo().top - this.height) + info.wrapper.removeChild(this.node); + if (info.panels.length == 0 && !skipRemove) removePanels(this.cm); + }; + + Panel.prototype.changed = function () { + this.height = this.node.getBoundingClientRect().height; + this.cm.setSize(); + }; + + function initPanels(cm) { + var wrap = cm.getWrapperElement() + var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle; + var height = parseInt(style.height); + var info = cm.state.panels = { + setHeight: wrap.style.height, + panels: [], + wrapper: document.createElement("div") + }; + var hasFocus = cm.hasFocus(), scrollPos = cm.getScrollInfo() + wrap.parentNode.insertBefore(info.wrapper, wrap); + info.wrapper.appendChild(wrap); + cm.scrollTo(scrollPos.left, scrollPos.top) + if (hasFocus) cm.focus(); + + cm._setSize = cm.setSize; + if (height != null) cm.setSize = function (width, newHeight) { + if (!newHeight) newHeight = info.wrapper.offsetHeight; + info.setHeight = newHeight; + if (typeof newHeight != "number") { + var px = /^(\d+\.?\d*)px$/.exec(newHeight); + if (px) { + newHeight = Number(px[1]); + } else { + info.wrapper.style.height = newHeight; + newHeight = info.wrapper.offsetHeight; + } + } + var editorheight = newHeight - info.panels + .map(function (p) { return p.node.getBoundingClientRect().height; }) + .reduce(function (a, b) { return a + b; }, 0); + cm._setSize(width, editorheight); + height = newHeight; + }; + } + + function removePanels(cm) { + var info = cm.state.panels; + cm.state.panels = null; + + var wrap = cm.getWrapperElement() + var hasFocus = cm.hasFocus(), scrollPos = cm.getScrollInfo() + info.wrapper.parentNode.replaceChild(wrap, info.wrapper); + cm.scrollTo(scrollPos.left, scrollPos.top) + if (hasFocus) cm.focus(); + wrap.style.height = info.setHeight; + cm.setSize = cm._setSize; + cm.setSize(); + } + + function isAtTop(cm, dom) { + for (var sibling = dom.nextSibling; sibling; sibling = sibling.nextSibling) + if (sibling == cm.getWrapperElement()) return true + return false + } +}); diff --git a/dcScript/codemirror/addon/display/placeholder.js b/dcScript/codemirror/addon/display/placeholder.js new file mode 100644 index 0000000..7848f51 --- /dev/null +++ b/dcScript/codemirror/addon/display/placeholder.js @@ -0,0 +1,78 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("placeholder", "", function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm.on("blur", onBlur); + cm.on("change", onChange); + cm.on("swapDoc", onChange); + CodeMirror.on(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose = function() { onComposition(cm) }) + onChange(cm); + } else if (!val && prev) { + cm.off("blur", onBlur); + cm.off("change", onChange); + cm.off("swapDoc", onChange); + CodeMirror.off(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose) + clearPlaceholder(cm); + var wrapper = cm.getWrapperElement(); + wrapper.className = wrapper.className.replace(" CodeMirror-empty", ""); + } + + if (val && !cm.hasFocus()) onBlur(cm); + }); + + function clearPlaceholder(cm) { + if (cm.state.placeholder) { + cm.state.placeholder.parentNode.removeChild(cm.state.placeholder); + cm.state.placeholder = null; + } + } + function setPlaceholder(cm) { + clearPlaceholder(cm); + var elt = cm.state.placeholder = document.createElement("pre"); + elt.style.cssText = "height: 0; overflow: visible"; + elt.style.direction = cm.getOption("direction"); + elt.className = "CodeMirror-placeholder CodeMirror-line-like"; + var placeHolder = cm.getOption("placeholder") + if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder) + elt.appendChild(placeHolder) + cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild); + } + + function onComposition(cm) { + setTimeout(function() { + var empty = false + if (cm.lineCount() == 1) { + var input = cm.getInputField() + empty = input.nodeName == "TEXTAREA" ? !cm.getLine(0).length + : !/[^\u200b]/.test(input.querySelector(".CodeMirror-line").textContent) + } + if (empty) setPlaceholder(cm) + else clearPlaceholder(cm) + }, 20) + } + + function onBlur(cm) { + if (isEmpty(cm)) setPlaceholder(cm); + } + function onChange(cm) { + var wrapper = cm.getWrapperElement(), empty = isEmpty(cm); + wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : ""); + + if (empty) setPlaceholder(cm); + else clearPlaceholder(cm); + } + + function isEmpty(cm) { + return (cm.lineCount() === 1) && (cm.getLine(0) === ""); + } +}); diff --git a/dcScript/codemirror/addon/display/rulers.js b/dcScript/codemirror/addon/display/rulers.js new file mode 100644 index 0000000..4ca15ea --- /dev/null +++ b/dcScript/codemirror/addon/display/rulers.js @@ -0,0 +1,51 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("rulers", false, function(cm, val) { + if (cm.state.rulerDiv) { + cm.state.rulerDiv.parentElement.removeChild(cm.state.rulerDiv) + cm.state.rulerDiv = null + cm.off("refresh", drawRulers) + } + if (val && val.length) { + cm.state.rulerDiv = cm.display.lineSpace.parentElement.insertBefore(document.createElement("div"), cm.display.lineSpace) + cm.state.rulerDiv.className = "CodeMirror-rulers" + drawRulers(cm) + cm.on("refresh", drawRulers) + } + }); + + function drawRulers(cm) { + cm.state.rulerDiv.textContent = "" + var val = cm.getOption("rulers"); + var cw = cm.defaultCharWidth(); + var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left; + cm.state.rulerDiv.style.minHeight = (cm.display.scroller.offsetHeight + 30) + "px"; + for (var i = 0; i < val.length; i++) { + var elt = document.createElement("div"); + elt.className = "CodeMirror-ruler"; + var col, conf = val[i]; + if (typeof conf == "number") { + col = conf; + } else { + col = conf.column; + if (conf.className) elt.className += " " + conf.className; + if (conf.color) elt.style.borderColor = conf.color; + if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle; + if (conf.width) elt.style.borderLeftWidth = conf.width; + } + elt.style.left = (left + col * cw) + "px"; + cm.state.rulerDiv.appendChild(elt) + } + } +}); diff --git a/dcScript/codemirror/addon/edit/closebrackets.js b/dcScript/codemirror/addon/edit/closebrackets.js new file mode 100644 index 0000000..badbbd8 --- /dev/null +++ b/dcScript/codemirror/addon/edit/closebrackets.js @@ -0,0 +1,201 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var defaults = { + pairs: "()[]{}''\"\"", + closeBefore: ")]}'\":;>", + triples: "", + explode: "[]{}" + }; + + var Pos = CodeMirror.Pos; + + CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.removeKeyMap(keyMap); + cm.state.closeBrackets = null; + } + if (val) { + ensureBound(getOption(val, "pairs")) + cm.state.closeBrackets = val; + cm.addKeyMap(keyMap); + } + }); + + function getOption(conf, name) { + if (name == "pairs" && typeof conf == "string") return conf; + if (typeof conf == "object" && conf[name] != null) return conf[name]; + return defaults[name]; + } + + var keyMap = {Backspace: handleBackspace, Enter: handleEnter}; + function ensureBound(chars) { + for (var i = 0; i < chars.length; i++) { + var ch = chars.charAt(i), key = "'" + ch + "'" + if (!keyMap[key]) keyMap[key] = handler(ch) + } + } + ensureBound(defaults.pairs + "`") + + function handler(ch) { + return function(cm) { return handleChar(cm, ch); }; + } + + function getConfig(cm) { + var deflt = cm.state.closeBrackets; + if (!deflt || deflt.override) return deflt; + var mode = cm.getModeAt(cm.getCursor()); + return mode.closeBrackets || deflt; + } + + function handleBackspace(cm) { + var conf = getConfig(cm); + if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; + + var pairs = getOption(conf, "pairs"); + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + for (var i = ranges.length - 1; i >= 0; i--) { + var cur = ranges[i].head; + cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete"); + } + } + + function handleEnter(cm) { + var conf = getConfig(cm); + var explode = conf && getOption(conf, "explode"); + if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass; + + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + cm.operation(function() { + var linesep = cm.lineSeparator() || "\n"; + cm.replaceSelection(linesep + linesep, null); + moveSel(cm, -1) + ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var line = ranges[i].head.line; + cm.indentLine(line, null, true); + cm.indentLine(line + 1, null, true); + } + }); + } + + function moveSel(cm, dir) { + var newRanges = [], ranges = cm.listSelections(), primary = 0 + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i] + if (range.head == cm.getCursor()) primary = i + var pos = range.head.ch || dir > 0 ? {line: range.head.line, ch: range.head.ch + dir} : {line: range.head.line - 1} + newRanges.push({anchor: pos, head: pos}) + } + cm.setSelections(newRanges, primary) + } + + function contractSelection(sel) { + var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0; + return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)), + head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))}; + } + + function handleChar(cm, ch) { + var conf = getConfig(cm); + if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; + + var pairs = getOption(conf, "pairs"); + var pos = pairs.indexOf(ch); + if (pos == -1) return CodeMirror.Pass; + + var closeBefore = getOption(conf,"closeBefore"); + + var triples = getOption(conf, "triples"); + + var identical = pairs.charAt(pos + 1) == ch; + var ranges = cm.listSelections(); + var opening = pos % 2 == 0; + + var type; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i], cur = range.head, curType; + var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); + if (opening && !range.empty()) { + curType = "surround"; + } else if ((identical || !opening) && next == ch) { + if (identical && stringStartsAfter(cm, cur)) + curType = "both"; + else if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch) + curType = "skipThree"; + else + curType = "skip"; + } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 && + cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch) { + if (cur.ch > 2 && /\bstring/.test(cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)))) return CodeMirror.Pass; + curType = "addFour"; + } else if (identical) { + var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur) + if (!CodeMirror.isWordChar(next) && prev != ch && !CodeMirror.isWordChar(prev)) curType = "both"; + else return CodeMirror.Pass; + } else if (opening && (next.length === 0 || /\s/.test(next) || closeBefore.indexOf(next) > -1)) { + curType = "both"; + } else { + return CodeMirror.Pass; + } + if (!type) type = curType; + else if (type != curType) return CodeMirror.Pass; + } + + var left = pos % 2 ? pairs.charAt(pos - 1) : ch; + var right = pos % 2 ? ch : pairs.charAt(pos + 1); + cm.operation(function() { + if (type == "skip") { + moveSel(cm, 1) + } else if (type == "skipThree") { + moveSel(cm, 3) + } else if (type == "surround") { + var sels = cm.getSelections(); + for (var i = 0; i < sels.length; i++) + sels[i] = left + sels[i] + right; + cm.replaceSelections(sels, "around"); + sels = cm.listSelections().slice(); + for (var i = 0; i < sels.length; i++) + sels[i] = contractSelection(sels[i]); + cm.setSelections(sels); + } else if (type == "both") { + cm.replaceSelection(left + right, null); + cm.triggerElectric(left + right); + moveSel(cm, -1) + } else if (type == "addFour") { + cm.replaceSelection(left + left + left + left, "before"); + moveSel(cm, 1) + } + }); + } + + function charsAround(cm, pos) { + var str = cm.getRange(Pos(pos.line, pos.ch - 1), + Pos(pos.line, pos.ch + 1)); + return str.length == 2 ? str : null; + } + + function stringStartsAfter(cm, pos) { + var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1)) + return /\bstring/.test(token.type) && token.start == pos.ch && + (pos.ch == 0 || !/\bstring/.test(cm.getTokenTypeAt(pos))) + } +}); diff --git a/dcScript/codemirror/addon/edit/closetag.js b/dcScript/codemirror/addon/edit/closetag.js new file mode 100644 index 0000000..62c0578 --- /dev/null +++ b/dcScript/codemirror/addon/edit/closetag.js @@ -0,0 +1,185 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +/** + * Tag-closer extension for CodeMirror. + * + * This extension adds an "autoCloseTags" option that can be set to + * either true to get the default behavior, or an object to further + * configure its behavior. + * + * These are supported options: + * + * `whenClosing` (default true) + * Whether to autoclose when the '/' of a closing tag is typed. + * `whenOpening` (default true) + * Whether to autoclose the tag when the final '>' of an opening + * tag is typed. + * `dontCloseTags` (default is empty tags for HTML, none for XML) + * An array of tag names that should not be autoclosed. + * `indentTags` (default is block tags for HTML, none for XML) + * An array of tag names that should, when opened, cause a + * blank line to be added inside the tag, and the blank line and + * closing line to be indented. + * `emptyTags` (default is none) + * An array of XML tag names that should be autoclosed with '/>'. + * + * See demos/closetag.html for a usage example. + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../fold/xml-fold")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../fold/xml-fold"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) { + if (old != CodeMirror.Init && old) + cm.removeKeyMap("autoCloseTags"); + if (!val) return; + var map = {name: "autoCloseTags"}; + if (typeof val != "object" || val.whenClosing !== false) + map["'/'"] = function(cm) { return autoCloseSlash(cm); }; + if (typeof val != "object" || val.whenOpening !== false) + map["'>'"] = function(cm) { return autoCloseGT(cm); }; + cm.addKeyMap(map); + }); + + var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", + "source", "track", "wbr"]; + var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4", + "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"]; + + function autoCloseGT(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), replacements = []; + var opt = cm.getOption("autoCloseTags"); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var pos = ranges[i].head, tok = cm.getTokenAt(pos); + var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; + var tagInfo = inner.mode.xmlCurrentTag && inner.mode.xmlCurrentTag(state) + var tagName = tagInfo && tagInfo.name + if (!tagName) return CodeMirror.Pass + + var html = inner.mode.configuration == "html"; + var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); + var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); + + if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); + var lowerTagName = tagName.toLowerCase(); + // Don't process the '>' at the end of an end-tag or self-closing tag + if (!tagName || + tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) || + tok.type == "tag" && tagInfo.close || + tok.string.indexOf("/") == (pos.ch - tok.start - 1) || // match something like + dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 || + closingTagExists(cm, inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state) || [], tagName, pos, true)) + return CodeMirror.Pass; + + var emptyTags = typeof opt == "object" && opt.emptyTags; + if (emptyTags && indexOf(emptyTags, tagName) > -1) { + replacements[i] = { text: "/>", newPos: CodeMirror.Pos(pos.line, pos.ch + 2) }; + continue; + } + + var indent = indentTags && indexOf(indentTags, lowerTagName) > -1; + replacements[i] = {indent: indent, + text: ">" + (indent ? "\n\n" : "") + "", + newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)}; + } + + var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnAutoClose); + for (var i = ranges.length - 1; i >= 0; i--) { + var info = replacements[i]; + cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert"); + var sel = cm.listSelections().slice(0); + sel[i] = {head: info.newPos, anchor: info.newPos}; + cm.setSelections(sel); + if (!dontIndentOnAutoClose && info.indent) { + cm.indentLine(info.newPos.line, null, true); + cm.indentLine(info.newPos.line + 1, null, true); + } + } + } + + function autoCloseCurrent(cm, typingSlash) { + var ranges = cm.listSelections(), replacements = []; + var head = typingSlash ? "/" : "") replacement += ">"; + replacements[i] = replacement; + } + cm.replaceSelections(replacements); + ranges = cm.listSelections(); + if (!dontIndentOnAutoClose) { + for (var i = 0; i < ranges.length; i++) + if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line) + cm.indentLine(ranges[i].head.line); + } + } + + function autoCloseSlash(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + return autoCloseCurrent(cm, true); + } + + CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); }; + + function indexOf(collection, elt) { + if (collection.indexOf) return collection.indexOf(elt); + for (var i = 0, e = collection.length; i < e; ++i) + if (collection[i] == elt) return i; + return -1; + } + + // If xml-fold is loaded, we use its functionality to try and verify + // whether a given tag is actually unclosed. + function closingTagExists(cm, context, tagName, pos, newTag) { + if (!CodeMirror.scanForClosingTag) return false; + var end = Math.min(cm.lastLine() + 1, pos.line + 500); + var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end); + if (!nextClose || nextClose.tag != tagName) return false; + // If the immediate wrapping context contains onCx instances of + // the same tag, a closing tag only exists if there are at least + // that many closing tags of that type following. + var onCx = newTag ? 1 : 0 + for (var i = context.length - 1; i >= 0; i--) { + if (context[i] == tagName) ++onCx + else break + } + pos = nextClose.to; + for (var i = 1; i < onCx; i++) { + var next = CodeMirror.scanForClosingTag(cm, pos, null, end); + if (!next || next.tag != tagName) return false; + pos = next.to; + } + return true; + } +}); diff --git a/dcScript/codemirror/addon/edit/continuelist.js b/dcScript/codemirror/addon/edit/continuelist.js new file mode 100644 index 0000000..915d813 --- /dev/null +++ b/dcScript/codemirror/addon/edit/continuelist.js @@ -0,0 +1,101 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var listRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/, + emptyListRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/, + unorderedListRE = /[*+-]\s/; + + CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), replacements = []; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].head; + + // If we're not in Markdown mode, fall back to normal newlineAndIndent + var eolState = cm.getStateAfter(pos.line); + var inner = CodeMirror.innerMode(cm.getMode(), eolState); + if (inner.mode.name !== "markdown" && inner.mode.helperType !== "markdown") { + cm.execCommand("newlineAndIndent"); + return; + } else { + eolState = inner.state; + } + + var inList = eolState.list !== false; + var inQuote = eolState.quote !== 0; + + var line = cm.getLine(pos.line), match = listRE.exec(line); + var cursorBeforeBullet = /^\s*$/.test(line.slice(0, pos.ch)); + if (!ranges[i].empty() || (!inList && !inQuote) || !match || cursorBeforeBullet) { + cm.execCommand("newlineAndIndent"); + return; + } + if (emptyListRE.test(line)) { + var endOfQuote = inQuote && />\s*$/.test(line) + var endOfList = !/>\s*$/.test(line) + if (endOfQuote || endOfList) cm.replaceRange("", { + line: pos.line, ch: 0 + }, { + line: pos.line, ch: pos.ch + 1 + }); + replacements[i] = "\n"; + } else { + var indent = match[1], after = match[5]; + var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0); + var bullet = numbered ? (parseInt(match[3], 10) + 1) + match[4] : match[2].replace("x", " "); + replacements[i] = "\n" + indent + bullet + after; + + if (numbered) incrementRemainingMarkdownListNumbers(cm, pos); + } + } + + cm.replaceSelections(replacements); + }; + + // Auto-updating Markdown list numbers when a new item is added to the + // middle of a list + function incrementRemainingMarkdownListNumbers(cm, pos) { + var startLine = pos.line, lookAhead = 0, skipCount = 0; + var startItem = listRE.exec(cm.getLine(startLine)), startIndent = startItem[1]; + + do { + lookAhead += 1; + var nextLineNumber = startLine + lookAhead; + var nextLine = cm.getLine(nextLineNumber), nextItem = listRE.exec(nextLine); + + if (nextItem) { + var nextIndent = nextItem[1]; + var newNumber = (parseInt(startItem[3], 10) + lookAhead - skipCount); + var nextNumber = (parseInt(nextItem[3], 10)), itemNumber = nextNumber; + + if (startIndent === nextIndent && !isNaN(nextNumber)) { + if (newNumber === nextNumber) itemNumber = nextNumber + 1; + if (newNumber > nextNumber) itemNumber = newNumber + 1; + cm.replaceRange( + nextLine.replace(listRE, nextIndent + itemNumber + nextItem[4] + nextItem[5]), + { + line: nextLineNumber, ch: 0 + }, { + line: nextLineNumber, ch: nextLine.length + }); + } else { + if (startIndent.length > nextIndent.length) return; + // This doesn't run if the next line immediately indents, as it is + // not clear of the users intention (new indented item or same level) + if ((startIndent.length < nextIndent.length) && (lookAhead === 1)) return; + skipCount += 1; + } + } + } while (nextItem); + } +}); diff --git a/dcScript/codemirror/addon/edit/matchbrackets.js b/dcScript/codemirror/addon/edit/matchbrackets.js index 2a14728..c342910 100644 --- a/dcScript/codemirror/addon/edit/matchbrackets.js +++ b/dcScript/codemirror/addon/edit/matchbrackets.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -38,7 +38,7 @@ if (config && config.strict && (dir > 0) != (pos == where.ch)) return null; var style = cm.getTokenTypeAt(Pos(where.line, pos + 1)); - var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config); + var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style, config); if (found == null) return null; return {from: Pos(where.line, pos), to: found && found.pos, match: found && found.ch == match.charAt(0), forward: dir > 0}; @@ -67,7 +67,8 @@ if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0); for (; pos != end; pos += dir) { var ch = line.charAt(pos); - if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) { + if (re.test(ch) && (style === undefined || + (cm.getTokenTypeAt(Pos(lineNo, pos + 1)) || "") == (style || ""))) { var match = matching[ch]; if (match && (match.charAt(1) == ">") == (dir > 0)) stack.push(ch); else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch}; @@ -80,11 +81,12 @@ function matchBrackets(cm, autoclear, config) { // Disable brace matching in long lines, since it'll cause hugely slow updates - var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000; + var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000, + highlightNonMatching = config && config.highlightNonMatching; var marks = [], ranges = cm.listSelections(); for (var i = 0; i < ranges.length; i++) { var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config); - if (match && cm.getLine(match.from.line).length <= maxHighlightLen) { + if (match && (match.match || highlightNonMatching !== false) && cm.getLine(match.from.line).length <= maxHighlightLen) { var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style})); if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen) @@ -94,7 +96,7 @@ if (marks.length) { // Kludge to work around the IE bug from issue #1193, where text - // input stops going to the textare whever this fires. + // input stops going to the textarea whenever this fires. if (ie_lt8 && cm.state.focused) cm.focus(); var clear = function() { @@ -117,17 +119,25 @@ }); } + function clearHighlighted(cm) { + if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) { + cm.state.matchBrackets.currentlyHighlighted(); + cm.state.matchBrackets.currentlyHighlighted = null; + } + } + CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { if (old && old != CodeMirror.Init) { cm.off("cursorActivity", doMatchBrackets); - if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) { - cm.state.matchBrackets.currentlyHighlighted(); - cm.state.matchBrackets.currentlyHighlighted = null; - } + cm.off("focus", doMatchBrackets) + cm.off("blur", clearHighlighted) + clearHighlighted(cm); } if (val) { cm.state.matchBrackets = typeof val == "object" ? val : {}; cm.on("cursorActivity", doMatchBrackets); + cm.on("focus", doMatchBrackets) + cm.on("blur", clearHighlighted) } }); diff --git a/dcScript/codemirror/addon/edit/matchtags.js b/dcScript/codemirror/addon/edit/matchtags.js index 2203d93..afa6105 100644 --- a/dcScript/codemirror/addon/edit/matchtags.js +++ b/dcScript/codemirror/addon/edit/matchtags.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/dcScript/codemirror/addon/edit/trailingspace.js b/dcScript/codemirror/addon/edit/trailingspace.js index c39c310..8d01c20 100644 --- a/dcScript/codemirror/addon/edit/trailingspace.js +++ b/dcScript/codemirror/addon/edit/trailingspace.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/dcScript/codemirror/addon/fold/brace-fold.js b/dcScript/codemirror/addon/fold/brace-fold.js index 654d1fb..2124768 100644 --- a/dcScript/codemirror/addon/fold/brace-fold.js +++ b/dcScript/codemirror/addon/fold/brace-fold.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -11,53 +11,67 @@ })(function(CodeMirror) { "use strict"; -CodeMirror.registerHelper("fold", "brace", function(cm, start) { - var line = start.line, lineText = cm.getLine(line); - var tokenType; +function bracketFolding(pairs) { + return function(cm, start) { + var line = start.line, lineText = cm.getLine(line); - function findOpening(openCh) { - for (var at = start.ch, pass = 0;;) { - var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1); - if (found == -1) { - if (pass == 1) break; - pass = 1; - at = lineText.length; - continue; + function findOpening(pair) { + var tokenType; + for (var at = start.ch, pass = 0;;) { + var found = at <= 0 ? -1 : lineText.lastIndexOf(pair[0], at - 1); + if (found == -1) { + if (pass == 1) break; + pass = 1; + at = lineText.length; + continue; + } + if (pass == 1 && found < start.ch) break; + tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)); + if (!/^(comment|string)/.test(tokenType)) return {ch: found + 1, tokenType: tokenType, pair: pair}; + at = found - 1; } - if (pass == 1 && found < start.ch) break; - tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)); - if (!/^(comment|string)/.test(tokenType)) return found + 1; - at = found - 1; } - } - - var startToken = "{", endToken = "}", startCh = findOpening("{"); - if (startCh == null) { - startToken = "[", endToken = "]"; - startCh = findOpening("["); - } - if (startCh == null) return; - var count = 1, lastLine = cm.lastLine(), end, endCh; - outer: for (var i = line; i <= lastLine; ++i) { - var text = cm.getLine(i), pos = i == line ? startCh : 0; - for (;;) { - var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); - if (nextOpen < 0) nextOpen = text.length; - if (nextClose < 0) nextClose = text.length; - pos = Math.min(nextOpen, nextClose); - if (pos == text.length) break; - if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) { - if (pos == nextOpen) ++count; - else if (!--count) { end = i; endCh = pos; break outer; } + function findRange(found) { + var count = 1, lastLine = cm.lastLine(), end, startCh = found.ch, endCh + outer: for (var i = line; i <= lastLine; ++i) { + var text = cm.getLine(i), pos = i == line ? startCh : 0; + for (;;) { + var nextOpen = text.indexOf(found.pair[0], pos), nextClose = text.indexOf(found.pair[1], pos); + if (nextOpen < 0) nextOpen = text.length; + if (nextClose < 0) nextClose = text.length; + pos = Math.min(nextOpen, nextClose); + if (pos == text.length) break; + if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == found.tokenType) { + if (pos == nextOpen) ++count; + else if (!--count) { end = i; endCh = pos; break outer; } + } + ++pos; + } } - ++pos; + + if (end == null || line == end) return null + return {from: CodeMirror.Pos(line, startCh), + to: CodeMirror.Pos(end, endCh)}; + } + + var found = [] + for (var i = 0; i < pairs.length; i++) { + var open = findOpening(pairs[i]) + if (open) found.push(open) + } + found.sort(function(a, b) { return a.ch - b.ch }) + for (var i = 0; i < found.length; i++) { + var range = findRange(found[i]) + if (range) return range } + return null } - if (end == null || line == end) return; - return {from: CodeMirror.Pos(line, startCh), - to: CodeMirror.Pos(end, endCh)}; -}); +} + +CodeMirror.registerHelper("fold", "brace", bracketFolding([["{", "}"], ["[", "]"]])); + +CodeMirror.registerHelper("fold", "brace-paren", bracketFolding([["{", "}"], ["[", "]"], ["(", ")"]])); CodeMirror.registerHelper("fold", "import", function(cm, start) { function hasImport(line) { diff --git a/dcScript/codemirror/addon/fold/comment-fold.js b/dcScript/codemirror/addon/fold/comment-fold.js index 836101d..adaa79d 100644 --- a/dcScript/codemirror/addon/fold/comment-fold.js +++ b/dcScript/codemirror/addon/fold/comment-fold.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/dcScript/codemirror/addon/fold/foldcode.js b/dcScript/codemirror/addon/fold/foldcode.js index 887df3f..a6a51af 100644 --- a/dcScript/codemirror/addon/fold/foldcode.js +++ b/dcScript/codemirror/addon/fold/foldcode.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -24,9 +24,11 @@ function getRange(allowFolded) { var range = finder(cm, pos); if (!range || range.to.line - range.from.line < minSize) return null; + if (force === "fold") return range; + var marks = cm.findMarksAt(range.from); for (var i = 0; i < marks.length; ++i) { - if (marks[i].__isFold && force !== "fold") { + if (marks[i].__isFold) { if (!allowFolded) return null; range.cleared = true; marks[i].clear(); @@ -99,18 +101,18 @@ cm.foldCode(cm.getCursor(), null, "fold"); }; CodeMirror.commands.unfold = function(cm) { - cm.foldCode(cm.getCursor(), null, "unfold"); + cm.foldCode(cm.getCursor(), { scanUp: false }, "unfold"); }; CodeMirror.commands.foldAll = function(cm) { cm.operation(function() { for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) - cm.foldCode(CodeMirror.Pos(i, 0), null, "fold"); + cm.foldCode(CodeMirror.Pos(i, 0), { scanUp: false }, "fold"); }); }; CodeMirror.commands.unfoldAll = function(cm) { cm.operation(function() { for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) - cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold"); + cm.foldCode(CodeMirror.Pos(i, 0), { scanUp: false }, "unfold"); }); }; diff --git a/dcScript/codemirror/addon/fold/foldgutter.css b/dcScript/codemirror/addon/fold/foldgutter.css new file mode 100644 index 0000000..ad19ae2 --- /dev/null +++ b/dcScript/codemirror/addon/fold/foldgutter.css @@ -0,0 +1,20 @@ +.CodeMirror-foldmarker { + color: blue; + text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px; + font-family: arial; + line-height: .3; + cursor: pointer; +} +.CodeMirror-foldgutter { + width: .7em; +} +.CodeMirror-foldgutter-open, +.CodeMirror-foldgutter-folded { + cursor: pointer; +} +.CodeMirror-foldgutter-open:after { + content: "\25BE"; +} +.CodeMirror-foldgutter-folded:after { + content: "\25B8"; +} diff --git a/dcScript/codemirror/addon/fold/foldgutter.js b/dcScript/codemirror/addon/fold/foldgutter.js index 7d46a60..8fc0e99 100644 --- a/dcScript/codemirror/addon/fold/foldgutter.js +++ b/dcScript/codemirror/addon/fold/foldgutter.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -21,6 +21,7 @@ cm.off("fold", onFold); cm.off("unfold", onFold); cm.off("swapDoc", onChange); + cm.off("optionChange", optionChange); } if (val) { cm.state.foldGutter = new State(parseOptions(val)); @@ -31,6 +32,7 @@ cm.on("fold", onFold); cm.on("unfold", onFold); cm.on("swapDoc", onChange); + cm.on("optionChange", optionChange); } }); @@ -120,6 +122,10 @@ else cm.foldCode(Pos(line, 0), opts); } + function optionChange(cm, option) { + if (option == "mode") onChange(cm) + } + function onChange(cm) { var state = cm.state.foldGutter; if (!state) return; diff --git a/dcScript/codemirror/addon/fold/indent-fold.js b/dcScript/codemirror/addon/fold/indent-fold.js index 0cc1126..470e84a 100644 --- a/dcScript/codemirror/addon/fold/indent-fold.js +++ b/dcScript/codemirror/addon/fold/indent-fold.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/dcScript/codemirror/addon/fold/markdown-fold.js b/dcScript/codemirror/addon/fold/markdown-fold.js new file mode 100644 index 0000000..4f9cb02 --- /dev/null +++ b/dcScript/codemirror/addon/fold/markdown-fold.js @@ -0,0 +1,49 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("fold", "markdown", function(cm, start) { + var maxDepth = 100; + + function isHeader(lineNo) { + var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0)); + return tokentype && /\bheader\b/.test(tokentype); + } + + function headerLevel(lineNo, line, nextLine) { + var match = line && line.match(/^#+/); + if (match && isHeader(lineNo)) return match[0].length; + match = nextLine && nextLine.match(/^[=\-]+\s*$/); + if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2; + return maxDepth; + } + + var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1); + var level = headerLevel(start.line, firstLine, nextLine); + if (level === maxDepth) return undefined; + + var lastLineNo = cm.lastLine(); + var end = start.line, nextNextLine = cm.getLine(end + 2); + while (end < lastLineNo) { + if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break; + ++end; + nextLine = nextNextLine; + nextNextLine = cm.getLine(end + 2); + } + + return { + from: CodeMirror.Pos(start.line, firstLine.length), + to: CodeMirror.Pos(end, cm.getLine(end).length) + }; +}); + +}); diff --git a/dcScript/codemirror/addon/fold/xml-fold.js b/dcScript/codemirror/addon/fold/xml-fold.js index 13bc383..5450d37 100644 --- a/dcScript/codemirror/addon/fold/xml-fold.js +++ b/dcScript/codemirror/addon/fold/xml-fold.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/dcScript/codemirror/addon/search/jump-to-line.js b/dcScript/codemirror/addon/search/jump-to-line.js new file mode 100644 index 0000000..596383b --- /dev/null +++ b/dcScript/codemirror/addon/search/jump-to-line.js @@ -0,0 +1,53 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +// Defines jumpToLine command. Uses dialog.js if present. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../dialog/dialog")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../dialog/dialog"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + // default search panel location + CodeMirror.defineOption("search", {bottom: false}); + + function dialog(cm, text, shortText, deflt, f) { + if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true, bottom: cm.options.search.bottom}); + else f(prompt(shortText, deflt)); + } + + function getJumpDialog(cm) { + return cm.phrase("Jump to line:") + ' ' + cm.phrase("(Use line:column or scroll% syntax)") + ''; + } + + function interpretLine(cm, string) { + var num = Number(string) + if (/^[-+]/.test(string)) return cm.getCursor().line + num + else return num - 1 + } + + CodeMirror.commands.jumpToLine = function(cm) { + var cur = cm.getCursor(); + dialog(cm, getJumpDialog(cm), cm.phrase("Jump to line:"), (cur.line + 1) + ":" + cur.ch, function(posStr) { + if (!posStr) return; + + var match; + if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) { + cm.setCursor(interpretLine(cm, match[1]), Number(match[2])) + } else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) { + var line = Math.round(cm.lineCount() * Number(match[1]) / 100); + if (/^[-+]/.test(match[1])) line = cur.line + line + 1; + cm.setCursor(line - 1, cur.ch); + } else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) { + cm.setCursor(interpretLine(cm, match[1]), cur.ch); + } + }); + }; + + CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine"; +}); diff --git a/dcScript/codemirror/addon/search/match-highlighter.js b/dcScript/codemirror/addon/search/match-highlighter.js new file mode 100644 index 0000000..f7e7fb3 --- /dev/null +++ b/dcScript/codemirror/addon/search/match-highlighter.js @@ -0,0 +1,167 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +// Highlighting text that matches the selection +// +// Defines an option highlightSelectionMatches, which, when enabled, +// will style strings that match the selection throughout the +// document. +// +// The option can be set to true to simply enable it, or to a +// {minChars, style, wordsOnly, showToken, delay} object to explicitly +// configure it. minChars is the minimum amount of characters that should be +// selected for the behavior to occur, and style is the token style to +// apply to the matches. This will be prefixed by "cm-" to create an +// actual CSS class name. If wordsOnly is enabled, the matches will be +// highlighted only if the selected text is a word. showToken, when enabled, +// will cause the current token to be highlighted when nothing is selected. +// delay is used to specify how much time to wait, in milliseconds, before +// highlighting the matches. If annotateScrollbar is enabled, the occurrences +// will be highlighted on the scrollbar via the matchesonscrollbar addon. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./matchesonscrollbar")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./matchesonscrollbar"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var defaults = { + style: "matchhighlight", + minChars: 2, + delay: 100, + wordsOnly: false, + annotateScrollbar: false, + showToken: false, + trim: true + } + + function State(options) { + this.options = {} + for (var name in defaults) + this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name] + this.overlay = this.timeout = null; + this.matchesonscroll = null; + this.active = false; + } + + CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + removeOverlay(cm); + clearTimeout(cm.state.matchHighlighter.timeout); + cm.state.matchHighlighter = null; + cm.off("cursorActivity", cursorActivity); + cm.off("focus", onFocus) + } + if (val) { + var state = cm.state.matchHighlighter = new State(val); + if (cm.hasFocus()) { + state.active = true + highlightMatches(cm) + } else { + cm.on("focus", onFocus) + } + cm.on("cursorActivity", cursorActivity); + } + }); + + function cursorActivity(cm) { + var state = cm.state.matchHighlighter; + if (state.active || cm.hasFocus()) scheduleHighlight(cm, state) + } + + function onFocus(cm) { + var state = cm.state.matchHighlighter + if (!state.active) { + state.active = true + scheduleHighlight(cm, state) + } + } + + function scheduleHighlight(cm, state) { + clearTimeout(state.timeout); + state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay); + } + + function addOverlay(cm, query, hasBoundary, style) { + var state = cm.state.matchHighlighter; + cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style)); + if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) { + var searchFor = hasBoundary ? new RegExp((/\w/.test(query.charAt(0)) ? "\\b" : "") + + query.replace(/[\\\[.+*?(){|^$]/g, "\\$&") + + (/\w/.test(query.charAt(query.length - 1)) ? "\\b" : "")) : query; + state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false, + {className: "CodeMirror-selection-highlight-scrollbar"}); + } + } + + function removeOverlay(cm) { + var state = cm.state.matchHighlighter; + if (state.overlay) { + cm.removeOverlay(state.overlay); + state.overlay = null; + if (state.matchesonscroll) { + state.matchesonscroll.clear(); + state.matchesonscroll = null; + } + } + } + + function highlightMatches(cm) { + cm.operation(function() { + var state = cm.state.matchHighlighter; + removeOverlay(cm); + if (!cm.somethingSelected() && state.options.showToken) { + var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken; + var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start; + while (start && re.test(line.charAt(start - 1))) --start; + while (end < line.length && re.test(line.charAt(end))) ++end; + if (start < end) + addOverlay(cm, line.slice(start, end), re, state.options.style); + return; + } + var from = cm.getCursor("from"), to = cm.getCursor("to"); + if (from.line != to.line) return; + if (state.options.wordsOnly && !isWord(cm, from, to)) return; + var selection = cm.getRange(from, to) + if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "") + if (selection.length >= state.options.minChars) + addOverlay(cm, selection, false, state.options.style); + }); + } + + function isWord(cm, from, to) { + var str = cm.getRange(from, to); + if (str.match(/^\w+$/) !== null) { + if (from.ch > 0) { + var pos = {line: from.line, ch: from.ch - 1}; + var chr = cm.getRange(pos, from); + if (chr.match(/\W/) === null) return false; + } + if (to.ch < cm.getLine(from.line).length) { + var pos = {line: to.line, ch: to.ch + 1}; + var chr = cm.getRange(to, pos); + if (chr.match(/\W/) === null) return false; + } + return true; + } else return false; + } + + function boundariesAround(stream, re) { + return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) && + (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos))); + } + + function makeOverlay(query, hasBoundary, style) { + return {token: function(stream) { + if (stream.match(query) && + (!hasBoundary || boundariesAround(stream, hasBoundary))) + return style; + stream.next(); + stream.skipTo(query.charAt(0)) || stream.skipToEnd(); + }}; + } +}); diff --git a/dcScript/codemirror/addon/search/matchesonscrollbar.css b/dcScript/codemirror/addon/search/matchesonscrollbar.css new file mode 100644 index 0000000..77932cc --- /dev/null +++ b/dcScript/codemirror/addon/search/matchesonscrollbar.css @@ -0,0 +1,8 @@ +.CodeMirror-search-match { + background: gold; + border-top: 1px solid orange; + border-bottom: 1px solid orange; + -moz-box-sizing: border-box; + box-sizing: border-box; + opacity: .5; +} diff --git a/dcScript/codemirror/addon/search/matchesonscrollbar.js b/dcScript/codemirror/addon/search/matchesonscrollbar.js new file mode 100644 index 0000000..acab47b --- /dev/null +++ b/dcScript/codemirror/addon/search/matchesonscrollbar.js @@ -0,0 +1,97 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) { + if (typeof options == "string") options = {className: options}; + if (!options) options = {}; + return new SearchAnnotation(this, query, caseFold, options); + }); + + function SearchAnnotation(cm, query, caseFold, options) { + this.cm = cm; + this.options = options; + var annotateOptions = {listenForChanges: false}; + for (var prop in options) annotateOptions[prop] = options[prop]; + if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match"; + this.annotation = cm.annotateScrollbar(annotateOptions); + this.query = query; + this.caseFold = caseFold; + this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1}; + this.matches = []; + this.update = null; + + this.findMatches(); + this.annotation.update(this.matches); + + var self = this; + cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); }); + } + + var MAX_MATCHES = 1000; + + SearchAnnotation.prototype.findMatches = function() { + if (!this.gap) return; + for (var i = 0; i < this.matches.length; i++) { + var match = this.matches[i]; + if (match.from.line >= this.gap.to) break; + if (match.to.line >= this.gap.from) this.matches.splice(i--, 1); + } + var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), {caseFold: this.caseFold, multiline: this.options.multiline}); + var maxMatches = this.options && this.options.maxMatches || MAX_MATCHES; + while (cursor.findNext()) { + var match = {from: cursor.from(), to: cursor.to()}; + if (match.from.line >= this.gap.to) break; + this.matches.splice(i++, 0, match); + if (this.matches.length > maxMatches) break; + } + this.gap = null; + }; + + function offsetLine(line, changeStart, sizeChange) { + if (line <= changeStart) return line; + return Math.max(changeStart, line + sizeChange); + } + + SearchAnnotation.prototype.onChange = function(change) { + var startLine = change.from.line; + var endLine = CodeMirror.changeEnd(change).line; + var sizeChange = endLine - change.to.line; + if (this.gap) { + this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line); + this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line); + } else { + this.gap = {from: change.from.line, to: endLine + 1}; + } + + if (sizeChange) for (var i = 0; i < this.matches.length; i++) { + var match = this.matches[i]; + var newFrom = offsetLine(match.from.line, startLine, sizeChange); + if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch); + var newTo = offsetLine(match.to.line, startLine, sizeChange); + if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch); + } + clearTimeout(this.update); + var self = this; + this.update = setTimeout(function() { self.updateAfterChange(); }, 250); + }; + + SearchAnnotation.prototype.updateAfterChange = function() { + this.findMatches(); + this.annotation.update(this.matches); + }; + + SearchAnnotation.prototype.clear = function() { + this.cm.off("change", this.changeHandler); + this.annotation.clear(); + }; +}); diff --git a/dcScript/codemirror/addon/search/search.js b/dcScript/codemirror/addon/search/search.js index cecdd52..9662b09 100644 --- a/dcScript/codemirror/addon/search/search.js +++ b/dcScript/codemirror/addon/search/search.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE // Define search commands. Depends on dialog.js or another // implementation of the openDialog method. @@ -19,6 +19,9 @@ })(function(CodeMirror) { "use strict"; + // default search panel location + CodeMirror.defineOption("search", {bottom: false}); + function searchOverlay(query, caseInsensitive) { if (typeof query == "string") query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g"); @@ -63,12 +66,13 @@ selectValueOnOpen: true, closeOnEnter: false, onClose: function() { clearSearch(cm); }, - onKeyDown: onKeyDown + onKeyDown: onKeyDown, + bottom: cm.options.search.bottom }); } function dialog(cm, text, shortText, deflt, f) { - if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true}); + if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true, bottom: cm.options.search.bottom}); else f(prompt(shortText, deflt)); } @@ -185,18 +189,46 @@ if (state.annotate) { state.annotate.clear(); state.annotate = null; } });} + function el(tag, attrs) { + var element = tag ? document.createElement(tag) : document.createDocumentFragment(); + for (var key in attrs) { + element[key] = attrs[key]; + } + for (var i = 2; i < arguments.length; i++) { + var child = arguments[i] + element.appendChild(typeof child == "string" ? document.createTextNode(child) : child); + } + return element; + } function getQueryDialog(cm) { - return '' + cm.phrase("Search:") + ' ' + cm.phrase("(Use /re/ syntax for regexp search)") + ''; + var label = el("label", {className: "CodeMirror-search-label"}, + cm.phrase("Search:"), + el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field", + id: "CodeMirror-search-field"})); + label.setAttribute("for","CodeMirror-search-field"); + return el("", null, label, " ", + el("span", {style: "color: #666", className: "CodeMirror-search-hint"}, + cm.phrase("(Use /re/ syntax for regexp search)"))); } function getReplaceQueryDialog(cm) { - return ' ' + cm.phrase("(Use /re/ syntax for regexp search)") + ''; + return el("", null, " ", + el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field"}), " ", + el("span", {style: "color: #666", className: "CodeMirror-search-hint"}, + cm.phrase("(Use /re/ syntax for regexp search)"))); } function getReplacementQueryDialog(cm) { - return '' + cm.phrase("With:") + ' '; + return el("", null, + el("span", {className: "CodeMirror-search-label"}, cm.phrase("With:")), " ", + el("input", {type: "text", "style": "width: 10em", className: "CodeMirror-search-field"})); } function getDoReplaceConfirm(cm) { - return '' + cm.phrase("Replace?") + ' '; + return el("", null, + el("span", {className: "CodeMirror-search-label"}, cm.phrase("Replace?")), " ", + el("button", {}, cm.phrase("Yes")), " ", + el("button", {}, cm.phrase("No")), " ", + el("button", {}, cm.phrase("All")), " ", + el("button", {}, cm.phrase("Stop"))); } function replaceAll(cm, query, text) { @@ -213,8 +245,11 @@ function replace(cm, all) { if (cm.getOption("readOnly")) return; var query = cm.getSelection() || getSearchState(cm).lastQuery; - var dialogText = '' + (all ? cm.phrase("Replace all:") : cm.phrase("Replace:")) + ''; - dialog(cm, dialogText + getReplaceQueryDialog(cm), dialogText, query, function(query) { + var dialogText = all ? cm.phrase("Replace all:") : cm.phrase("Replace:") + var fragment = el("", null, + el("span", {className: "CodeMirror-search-label"}, dialogText), + getReplaceQueryDialog(cm)) + dialog(cm, fragment, dialogText, query, function(query) { if (!query) return; query = parseQuery(query); dialog(cm, getReplacementQueryDialog(cm), cm.phrase("Replace with:"), "", function(text) { diff --git a/dcScript/codemirror/addon/search/searchcursor.js b/dcScript/codemirror/addon/search/searchcursor.js index 816bf77..ffe6932 100644 --- a/dcScript/codemirror/addon/search/searchcursor.js +++ b/dcScript/codemirror/addon/search/searchcursor.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -202,6 +202,7 @@ function SearchCursor(doc, query, pos, options) { this.atOccurrence = false + this.afterEmptyMatch = false this.doc = doc pos = pos ? doc.clipPos(pos) : Pos(0, 0) this.pos = {from: pos, to: pos} @@ -237,21 +238,29 @@ findPrevious: function() {return this.find(true)}, find: function(reverse) { - var result = this.matches(reverse, this.doc.clipPos(reverse ? this.pos.from : this.pos.to)) - - // Implements weird auto-growing behavior on null-matches for - // backwards-compatiblity with the vim code (unfortunately) - while (result && CodeMirror.cmpPos(result.from, result.to) == 0) { + var head = this.doc.clipPos(reverse ? this.pos.from : this.pos.to); + if (this.afterEmptyMatch && this.atOccurrence) { + // do not return the same 0 width match twice + head = Pos(head.line, head.ch) if (reverse) { - if (result.from.ch) result.from = Pos(result.from.line, result.from.ch - 1) - else if (result.from.line == this.doc.firstLine()) result = null - else result = this.matches(reverse, this.doc.clipPos(Pos(result.from.line - 1))) + head.ch--; + if (head.ch < 0) { + head.line--; + head.ch = (this.doc.getLine(head.line) || "").length; + } } else { - if (result.to.ch < this.doc.getLine(result.to.line).length) result.to = Pos(result.to.line, result.to.ch + 1) - else if (result.to.line == this.doc.lastLine()) result = null - else result = this.matches(reverse, Pos(result.to.line + 1, 0)) + head.ch++; + if (head.ch > (this.doc.getLine(head.line) || "").length) { + head.ch = 0; + head.line++; + } + } + if (CodeMirror.cmpPos(head, this.doc.clipPos(head)) != 0) { + return this.atOccurrence = false } } + var result = this.matches(reverse, head) + this.afterEmptyMatch = result && CodeMirror.cmpPos(result.from, result.to) == 0 if (result) { this.pos = result diff --git a/dcScript/codemirror/addon/selection/active-line.js b/dcScript/codemirror/addon/selection/active-line.js index c7b14ce..ff81ffc 100644 --- a/dcScript/codemirror/addon/selection/active-line.js +++ b/dcScript/codemirror/addon/selection/active-line.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/dcScript/codemirror/addon/selection/mark-selection.js b/dcScript/codemirror/addon/selection/mark-selection.js new file mode 100644 index 0000000..fc80159 --- /dev/null +++ b/dcScript/codemirror/addon/selection/mark-selection.js @@ -0,0 +1,119 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +// Because sometimes you need to mark the selected *text*. +// +// Adds an option 'styleSelectedText' which, when enabled, gives +// selected text the CSS class given as option value, or +// "CodeMirror-selectedtext" when the value is not a string. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm.state.markedSelection = []; + cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext"; + reset(cm); + cm.on("cursorActivity", onCursorActivity); + cm.on("change", onChange); + } else if (!val && prev) { + cm.off("cursorActivity", onCursorActivity); + cm.off("change", onChange); + clear(cm); + cm.state.markedSelection = cm.state.markedSelectionStyle = null; + } + }); + + function onCursorActivity(cm) { + if (cm.state.markedSelection) + cm.operation(function() { update(cm); }); + } + + function onChange(cm) { + if (cm.state.markedSelection && cm.state.markedSelection.length) + cm.operation(function() { clear(cm); }); + } + + var CHUNK_SIZE = 8; + var Pos = CodeMirror.Pos; + var cmp = CodeMirror.cmpPos; + + function coverRange(cm, from, to, addAt) { + if (cmp(from, to) == 0) return; + var array = cm.state.markedSelection; + var cls = cm.state.markedSelectionStyle; + for (var line = from.line;;) { + var start = line == from.line ? from : Pos(line, 0); + var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line; + var end = atEnd ? to : Pos(endLine, 0); + var mark = cm.markText(start, end, {className: cls}); + if (addAt == null) array.push(mark); + else array.splice(addAt++, 0, mark); + if (atEnd) break; + line = endLine; + } + } + + function clear(cm) { + var array = cm.state.markedSelection; + for (var i = 0; i < array.length; ++i) array[i].clear(); + array.length = 0; + } + + function reset(cm) { + clear(cm); + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) + coverRange(cm, ranges[i].from(), ranges[i].to()); + } + + function update(cm) { + if (!cm.somethingSelected()) return clear(cm); + if (cm.listSelections().length > 1) return reset(cm); + + var from = cm.getCursor("start"), to = cm.getCursor("end"); + + var array = cm.state.markedSelection; + if (!array.length) return coverRange(cm, from, to); + + var coverStart = array[0].find(), coverEnd = array[array.length - 1].find(); + if (!coverStart || !coverEnd || to.line - from.line <= CHUNK_SIZE || + cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0) + return reset(cm); + + while (cmp(from, coverStart.from) > 0) { + array.shift().clear(); + coverStart = array[0].find(); + } + if (cmp(from, coverStart.from) < 0) { + if (coverStart.to.line - from.line < CHUNK_SIZE) { + array.shift().clear(); + coverRange(cm, from, coverStart.to, 0); + } else { + coverRange(cm, from, coverStart.from, 0); + } + } + + while (cmp(to, coverEnd.to) < 0) { + array.pop().clear(); + coverEnd = array[array.length - 1].find(); + } + if (cmp(to, coverEnd.to) > 0) { + if (to.line - coverEnd.from.line < CHUNK_SIZE) { + array.pop().clear(); + coverRange(cm, coverEnd.from, to); + } else { + coverRange(cm, coverEnd.to, to); + } + } + } +}); diff --git a/dcScript/codemirror/addon/selection/selection-pointer.js b/dcScript/codemirror/addon/selection/selection-pointer.js new file mode 100644 index 0000000..924b465 --- /dev/null +++ b/dcScript/codemirror/addon/selection/selection-pointer.js @@ -0,0 +1,98 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("selectionPointer", false, function(cm, val) { + var data = cm.state.selectionPointer; + if (data) { + CodeMirror.off(cm.getWrapperElement(), "mousemove", data.mousemove); + CodeMirror.off(cm.getWrapperElement(), "mouseout", data.mouseout); + CodeMirror.off(window, "scroll", data.windowScroll); + cm.off("cursorActivity", reset); + cm.off("scroll", reset); + cm.state.selectionPointer = null; + cm.display.lineDiv.style.cursor = ""; + } + if (val) { + data = cm.state.selectionPointer = { + value: typeof val == "string" ? val : "default", + mousemove: function(event) { mousemove(cm, event); }, + mouseout: function(event) { mouseout(cm, event); }, + windowScroll: function() { reset(cm); }, + rects: null, + mouseX: null, mouseY: null, + willUpdate: false + }; + CodeMirror.on(cm.getWrapperElement(), "mousemove", data.mousemove); + CodeMirror.on(cm.getWrapperElement(), "mouseout", data.mouseout); + CodeMirror.on(window, "scroll", data.windowScroll); + cm.on("cursorActivity", reset); + cm.on("scroll", reset); + } + }); + + function mousemove(cm, event) { + var data = cm.state.selectionPointer; + if (event.buttons == null ? event.which : event.buttons) { + data.mouseX = data.mouseY = null; + } else { + data.mouseX = event.clientX; + data.mouseY = event.clientY; + } + scheduleUpdate(cm); + } + + function mouseout(cm, event) { + if (!cm.getWrapperElement().contains(event.relatedTarget)) { + var data = cm.state.selectionPointer; + data.mouseX = data.mouseY = null; + scheduleUpdate(cm); + } + } + + function reset(cm) { + cm.state.selectionPointer.rects = null; + scheduleUpdate(cm); + } + + function scheduleUpdate(cm) { + if (!cm.state.selectionPointer.willUpdate) { + cm.state.selectionPointer.willUpdate = true; + setTimeout(function() { + update(cm); + cm.state.selectionPointer.willUpdate = false; + }, 50); + } + } + + function update(cm) { + var data = cm.state.selectionPointer; + if (!data) return; + if (data.rects == null && data.mouseX != null) { + data.rects = []; + if (cm.somethingSelected()) { + for (var sel = cm.display.selectionDiv.firstChild; sel; sel = sel.nextSibling) + data.rects.push(sel.getBoundingClientRect()); + } + } + var inside = false; + if (data.mouseX != null) for (var i = 0; i < data.rects.length; i++) { + var rect = data.rects[i]; + if (rect.left <= data.mouseX && rect.right >= data.mouseX && + rect.top <= data.mouseY && rect.bottom >= data.mouseY) + inside = true; + } + var cursor = inside ? data.value : ""; + if (cm.display.lineDiv.style.cursor != cursor) + cm.display.lineDiv.style.cursor = cursor; + } +}); diff --git a/dcScript/codemirror/lib/codemirror.css b/dcScript/codemirror/lib/codemirror.css index bc910fb..f4d5718 100644 --- a/dcScript/codemirror/lib/codemirror.css +++ b/dcScript/codemirror/lib/codemirror.css @@ -60,20 +60,13 @@ .cm-fat-cursor div.CodeMirror-cursors { z-index: 1; } -.cm-fat-cursor-mark { - background-color: rgba(20, 255, 20, 0.5); - -webkit-animation: blink 1.06s steps(1) infinite; - -moz-animation: blink 1.06s steps(1) infinite; - animation: blink 1.06s steps(1) infinite; -} -.cm-animate-fat-cursor { - width: auto; - border: 0; - -webkit-animation: blink 1.06s steps(1) infinite; - -moz-animation: blink 1.06s steps(1) infinite; - animation: blink 1.06s steps(1) infinite; - background-color: #7e7; -} +.cm-fat-cursor .CodeMirror-line::selection, +.cm-fat-cursor .CodeMirror-line > span::selection, +.cm-fat-cursor .CodeMirror-line > span > span::selection { background: transparent; } +.cm-fat-cursor .CodeMirror-line::-moz-selection, +.cm-fat-cursor .CodeMirror-line > span::-moz-selection, +.cm-fat-cursor .CodeMirror-line > span > span::-moz-selection { background: transparent; } +.cm-fat-cursor { caret-color: transparent; } @-moz-keyframes blink { 0% {} 50% { background-color: transparent; } @@ -164,17 +157,18 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} .CodeMirror-scroll { overflow: scroll !important; /* Things will break if this is overridden */ - /* 30px is the magic margin used to hide the element's real scrollbars */ + /* 50px is the magic margin used to hide the element's real scrollbars */ /* See overflow: hidden in .CodeMirror */ - margin-bottom: -30px; margin-right: -30px; - padding-bottom: 30px; + margin-bottom: -50px; margin-right: -50px; + padding-bottom: 50px; height: 100%; outline: none; /* Prevent dragging from highlighting the element */ position: relative; + z-index: 0; } .CodeMirror-sizer { position: relative; - border-right: 30px solid transparent; + border-right: 50px solid transparent; } /* The fake, visible scrollbars. Used to force redraw during scrolling @@ -184,6 +178,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} position: absolute; z-index: 6; display: none; + outline: none; } .CodeMirror-vscrollbar { right: 0; top: 0; @@ -212,7 +207,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} height: 100%; display: inline-block; vertical-align: top; - margin-bottom: -30px; + margin-bottom: -50px; } .CodeMirror-gutter-wrapper { position: absolute; diff --git a/dcScript/codemirror/lib/codemirror.js b/dcScript/codemirror/lib/codemirror.js index 9489e39..5ca96da 100644 --- a/dcScript/codemirror/lib/codemirror.js +++ b/dcScript/codemirror/lib/codemirror.js @@ -1,7 +1,7 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE -// This is CodeMirror (https://codemirror.net), a code editor +// This is CodeMirror (https://codemirror.net/5), a code editor // implemented in JavaScript on top of the browser's DOM. // // You can find some technical background for some of the code below @@ -10,7 +10,7 @@ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : - (global.CodeMirror = factory()); + (global = global || self, global.CodeMirror = factory()); }(this, (function () { 'use strict'; // Kludges for bugs and behavior differences that can't be feature @@ -26,13 +26,14 @@ var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]); var webkit = !edge && /WebKit\//.test(userAgent); var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent); - var chrome = !edge && /Chrome\//.test(userAgent); + var chrome = !edge && /Chrome\/(\d+)/.exec(userAgent); + var chrome_version = chrome && +chrome[1]; var presto = /Opera\//.test(userAgent); var safari = /Apple Computer/.test(navigator.vendor); var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent); var phantom = /PhantomJS/.test(userAgent); - var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent); + var ios = safari && (/Mobile\/\w+/.test(userAgent) || navigator.maxTouchPoints > 2); var android = /Android/.test(userAgent); // This is woefully incomplete. Suggestions for alternative methods welcome. var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent); @@ -111,15 +112,15 @@ } while (child = child.parentNode) } - function activeElt() { + function activeElt(doc) { // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement. // IE < 10 will throw when accessed while the page is loading or in an iframe. // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable. var activeElement; try { - activeElement = document.activeElement; + activeElement = doc.activeElement; } catch(e) { - activeElement = document.body || null; + activeElement = doc.body || null; } while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement) { activeElement = activeElement.shadowRoot.activeElement; } @@ -143,6 +144,10 @@ else if (ie) // Suppress mysterious IE10 errors { selectInput = function(node) { try { node.select(); } catch(_e) {} }; } + function doc(cm) { return cm.display.wrapper.ownerDocument } + + function win(cm) { return doc(cm).defaultView } + function bind(f) { var args = Array.prototype.slice.call(arguments, 1); return function(){return f.apply(null, args)} @@ -204,7 +209,7 @@ } // Number of pixels added to scroller and sizer to hide scrollbar - var scrollerGap = 30; + var scrollerGap = 50; // Returned or thrown by various protocols to signal 'I'm not // handling this'. @@ -537,8 +542,8 @@ } else if (emitter.attachEvent) { emitter.attachEvent("on" + type, f); } else { - var map$$1 = emitter._handlers || (emitter._handlers = {}); - map$$1[type] = (map$$1[type] || noHandlers).concat(f); + var map = emitter._handlers || (emitter._handlers = {}); + map[type] = (map[type] || noHandlers).concat(f); } }; @@ -552,11 +557,11 @@ } else if (emitter.detachEvent) { emitter.detachEvent("on" + type, f); } else { - var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type]; + var map = emitter._handlers, arr = map && map[type]; if (arr) { var index = indexOf(arr, f); if (index > -1) - { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); } + { map[type] = arr.slice(0, index).concat(arr.slice(index + 1)); } } } } @@ -684,11 +689,11 @@ try { return te.selectionStart != te.selectionEnd } catch(e) { return false } } : function (te) { - var range$$1; - try {range$$1 = te.ownerDocument.selection.createRange();} + var range; + try {range = te.ownerDocument.selection.createRange();} catch(e) {} - if (!range$$1 || range$$1.parentElement() != te) { return false } - return range$$1.compareEndPoints("StartToEnd", range$$1) != 0 + if (!range || range.parentElement() != te) { return false } + return range.compareEndPoints("StartToEnd", range) != 0 }; var hasCopyEvent = (function () { @@ -836,10 +841,8 @@ return this.pos > start }; StringStream.prototype.eatSpace = function () { - var this$1 = this; - var start = this.pos; - while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos; } + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this.pos; } return this.pos > start }; StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;}; @@ -1035,11 +1038,9 @@ }; Context.prototype.baseToken = function (n) { - var this$1 = this; - if (!this.baseTokens) { return null } while (this.baseTokens[this.baseTokenPos] <= n) - { this$1.baseTokenPos += 2; } + { this.baseTokenPos += 2; } var type = this.baseTokens[this.baseTokenPos + 1]; return {type: type && type.replace(/( |^)overlay .*/, ""), size: this.baseTokens[this.baseTokenPos] - n} @@ -1205,7 +1206,7 @@ var prop = lineClass[1] ? "bgClass" : "textClass"; if (output[prop] == null) { output[prop] = lineClass[2]; } - else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) + else if (!(new RegExp("(?:^|\\s)" + lineClass[2] + "(?:$|\\s)")).test(output[prop])) { output[prop] += " " + lineClass[2]; } } } return type @@ -1315,6 +1316,7 @@ if (span.marker == marker) { return span } } } } + // Remove a span from an array, returning undefined if no spans are // left (we don't store arrays for lines without spans). function removeMarkedSpan(spans, span) { @@ -1323,9 +1325,16 @@ { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } } return r } + // Add a span to a line. - function addMarkedSpan(line, span) { - line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; + function addMarkedSpan(line, span, op) { + var inThisOp = op && window.WeakSet && (op.markedSpans || (op.markedSpans = new WeakSet)); + if (inThisOp && line.markedSpans && inThisOp.has(line.markedSpans)) { + line.markedSpans.push(span); + } else { + line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; + if (inThisOp) { inThisOp.add(line.markedSpans); } + } span.marker.attachLine(line); } @@ -1528,8 +1537,8 @@ // Test whether there exists a collapsed span that partially // overlaps (covers the start or end, but not both) of a new span. // Such overlap is not allowed. - function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) { - var line = getLine(doc, lineNo$$1); + function conflictingCollapsedRange(doc, lineNo, from, to, marker) { + var line = getLine(doc, lineNo); var sps = sawCollapsedSpans && line.markedSpans; if (sps) { for (var i = 0; i < sps.length; ++i) { var sp = sps[i]; @@ -1845,7 +1854,7 @@ } } builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32; - if (style || startStyle || endStyle || mustWrap || css) { + if (style || startStyle || endStyle || mustWrap || css || attributes) { var fullStyle = style || ""; if (startStyle) { fullStyle += startStyle; } if (endStyle) { fullStyle += endStyle; } @@ -2190,6 +2199,7 @@ if (cm.options.lineNumbers || markers) { var wrap$1 = ensureLineWrapped(lineView); var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px")); + gutterWrap.setAttribute("aria-hidden", "true"); cm.display.input.setUneditable(gutterWrap); wrap$1.insertBefore(gutterWrap, lineView.text); if (lineView.line.gutterClass) @@ -2346,12 +2356,14 @@ function mapFromLineView(lineView, line, lineN) { if (lineView.line == line) { return {map: lineView.measure.map, cache: lineView.measure.cache} } - for (var i = 0; i < lineView.rest.length; i++) - { if (lineView.rest[i] == line) - { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } } - for (var i$1 = 0; i$1 < lineView.rest.length; i$1++) - { if (lineNo(lineView.rest[i$1]) > lineN) - { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } } + if (lineView.rest) { + for (var i = 0; i < lineView.rest.length; i++) + { if (lineView.rest[i] == line) + { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } } + for (var i$1 = 0; i$1 < lineView.rest.length; i$1++) + { if (lineNo(lineView.rest[i$1]) > lineN) + { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } } + } } // Render a line into the hidden node display.externalMeasured. Used @@ -2431,36 +2443,36 @@ var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; - function nodeAndOffsetInLineMap(map$$1, ch, bias) { + function nodeAndOffsetInLineMap(map, ch, bias) { var node, start, end, collapse, mStart, mEnd; // First, search the line map for the text node corresponding to, // or closest to, the target character. - for (var i = 0; i < map$$1.length; i += 3) { - mStart = map$$1[i]; - mEnd = map$$1[i + 1]; + for (var i = 0; i < map.length; i += 3) { + mStart = map[i]; + mEnd = map[i + 1]; if (ch < mStart) { start = 0; end = 1; collapse = "left"; } else if (ch < mEnd) { start = ch - mStart; end = start + 1; - } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) { + } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { end = mEnd - mStart; start = end - 1; if (ch >= mEnd) { collapse = "right"; } } if (start != null) { - node = map$$1[i + 2]; + node = map[i + 2]; if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) { collapse = bias; } if (bias == "left" && start == 0) - { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) { - node = map$$1[(i -= 3) + 2]; + { while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { + node = map[(i -= 3) + 2]; collapse = "left"; } } if (bias == "right" && start == mEnd - mStart) - { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) { - node = map$$1[(i += 3) + 2]; + { while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { + node = map[(i += 3) + 2]; collapse = "right"; } } break @@ -2565,22 +2577,24 @@ cm.display.lineNumChars = null; } - function pageScrollX() { + function pageScrollX(doc) { // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206 // which causes page_Offset and bounding client rects to use // different reference viewports and invalidate our calculations. - if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) } - return window.pageXOffset || (document.documentElement || document.body).scrollLeft + if (chrome && android) { return -(doc.body.getBoundingClientRect().left - parseInt(getComputedStyle(doc.body).marginLeft)) } + return doc.defaultView.pageXOffset || (doc.documentElement || doc.body).scrollLeft } - function pageScrollY() { - if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) } - return window.pageYOffset || (document.documentElement || document.body).scrollTop + function pageScrollY(doc) { + if (chrome && android) { return -(doc.body.getBoundingClientRect().top - parseInt(getComputedStyle(doc.body).marginTop)) } + return doc.defaultView.pageYOffset || (doc.documentElement || doc.body).scrollTop } function widgetTopHeight(lineObj) { + var ref = visualLine(lineObj); + var widgets = ref.widgets; var height = 0; - if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) - { height += widgetHeight(lineObj.widgets[i]); } } } + if (widgets) { for (var i = 0; i < widgets.length; ++i) { if (widgets[i].above) + { height += widgetHeight(widgets[i]); } } } return height } @@ -2600,8 +2614,8 @@ else { yOff -= cm.display.viewOffset; } if (context == "page" || context == "window") { var lOff = cm.display.lineSpace.getBoundingClientRect(); - yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); - var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); + yOff += lOff.top + (context == "window" ? 0 : pageScrollY(doc(cm))); + var xOff = lOff.left + (context == "window" ? 0 : pageScrollX(doc(cm))); rect.left += xOff; rect.right += xOff; } rect.top += yOff; rect.bottom += yOff; @@ -2615,8 +2629,8 @@ var left = coords.left, top = coords.top; // First move into "page" coordinate system if (context == "page") { - left -= pageScrollX(); - top -= pageScrollY(); + left -= pageScrollX(doc(cm)); + top -= pageScrollY(doc(cm)); } else if (context == "local" || !context) { var localBox = cm.display.sizer.getBoundingClientRect(); left += localBox.left; @@ -2743,13 +2757,13 @@ return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x } - function coordsCharInner(cm, lineObj, lineNo$$1, x, y) { + function coordsCharInner(cm, lineObj, lineNo, x, y) { // Move y into line-local coordinate space y -= heightAtLine(lineObj); var preparedMeasure = prepareMeasureForLine(cm, lineObj); // When directly calling `measureCharPrepared`, we have to adjust // for the widgets at this line. - var widgetHeight$$1 = widgetTopHeight(lineObj); + var widgetHeight = widgetTopHeight(lineObj); var begin = 0, end = lineObj.text.length, ltr = true; var order = getOrder(lineObj, cm.doc.direction); @@ -2757,7 +2771,7 @@ // which bidi section the coordinates fall into. if (order) { var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart) - (cm, lineObj, lineNo$$1, preparedMeasure, order, x, y); + (cm, lineObj, lineNo, preparedMeasure, order, x, y); ltr = part.level != 1; // The awkward -1 offsets are needed because findFirst (called // on these below) will treat its first bound as inclusive, @@ -2773,7 +2787,7 @@ var chAround = null, boxAround = null; var ch = findFirst(function (ch) { var box = measureCharPrepared(cm, preparedMeasure, ch); - box.top += widgetHeight$$1; box.bottom += widgetHeight$$1; + box.top += widgetHeight; box.bottom += widgetHeight; if (!boxIsAfter(box, x, y, false)) { return false } if (box.top <= y && box.left <= x) { chAround = ch; @@ -2797,27 +2811,27 @@ // left of the character and compare it's vertical position to the // coordinates sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" : - (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight$$1 <= y) == ltr ? + (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ? "after" : "before"; // Now get accurate coordinates for this place, in order to get a // base X position - var coords = cursorCoords(cm, Pos(lineNo$$1, ch, sticky), "line", lineObj, preparedMeasure); + var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure); baseX = coords.left; outside = y < coords.top ? -1 : y >= coords.bottom ? 1 : 0; } ch = skipExtendingChars(lineObj.text, ch, 1); - return PosWithInfo(lineNo$$1, ch, sticky, outside, x - baseX) + return PosWithInfo(lineNo, ch, sticky, outside, x - baseX) } - function coordsBidiPart(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y) { + function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) { // Bidi parts are sorted left-to-right, and in a non-line-wrapping // situation, we can take this ordering to correspond to the visual // ordering. This finds the first part whose end is after the given // coordinates. var index = findFirst(function (i) { var part = order[i], ltr = part.level != 1; - return boxIsAfter(cursorCoords(cm, Pos(lineNo$$1, ltr ? part.to : part.from, ltr ? "before" : "after"), + return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"), "line", lineObj, preparedMeasure), x, y, true) }, 0, order.length - 1); var part = order[index]; @@ -2826,7 +2840,7 @@ // that start, move one part back. if (index > 0) { var ltr = part.level != 1; - var start = cursorCoords(cm, Pos(lineNo$$1, ltr ? part.from : part.to, ltr ? "after" : "before"), + var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"), "line", lineObj, preparedMeasure); if (boxIsAfter(start, x, y, true) && start.top > y) { part = order[index - 1]; } @@ -2964,7 +2978,7 @@ var x, y, space = display.lineSpace.getBoundingClientRect(); // Fails unpredictably on IE[67] when mouse is dragged around quickly. try { x = e.clientX - space.left; y = e.clientY - space.top; } - catch (e) { return null } + catch (e$1) { return null } var coords = coordsChar(cm, x, y), line; if (forRect && coords.xRel > 0 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; @@ -3145,15 +3159,21 @@ var curFragment = result.cursors = document.createDocumentFragment(); var selFragment = result.selection = document.createDocumentFragment(); + var customCursor = cm.options.$customCursor; + if (customCursor) { primary = true; } for (var i = 0; i < doc.sel.ranges.length; i++) { if (!primary && i == doc.sel.primIndex) { continue } - var range$$1 = doc.sel.ranges[i]; - if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue } - var collapsed = range$$1.empty(); - if (collapsed || cm.options.showCursorWhenSelecting) - { drawSelectionCursor(cm, range$$1.head, curFragment); } + var range = doc.sel.ranges[i]; + if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue } + var collapsed = range.empty(); + if (customCursor) { + var head = customCursor(cm, range); + if (head) { drawSelectionCursor(cm, head, curFragment); } + } else if (collapsed || cm.options.showCursorWhenSelecting) { + drawSelectionCursor(cm, range.head, curFragment); + } if (!collapsed) - { drawSelectionRange(cm, range$$1, selFragment); } + { drawSelectionRange(cm, range, selFragment); } } return result } @@ -3167,6 +3187,12 @@ cursor.style.top = pos.top + "px"; cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; + if (/\bcm-fat-cursor\b/.test(cm.getWrapperElement().className)) { + var charPos = charCoords(cm, head, "div", null, null); + var width = charPos.right - charPos.left; + cursor.style.width = (width > 0 ? width : cm.defaultCharWidth()) + "px"; + } + if (pos.other) { // Secondary cursor, shown when on a 'jump' in bi-directional text var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); @@ -3180,7 +3206,7 @@ function cmpCoords(a, b) { return a.top - b.top || a.left - b.left } // Draws the given range as a highlighted selection - function drawSelectionRange(cm, range$$1, output) { + function drawSelectionRange(cm, range, output) { var display = cm.display, doc = cm.doc; var fragment = document.createDocumentFragment(); var padding = paddingH(cm.display), leftSide = padding.left; @@ -3249,7 +3275,7 @@ return {start: start, end: end} } - var sFrom = range$$1.from(), sTo = range$$1.to(); + var sFrom = range.from(), sTo = range.to(); if (sFrom.line == sTo.line) { drawForLine(sFrom.line, sFrom.ch, sTo.ch); } else { @@ -3280,26 +3306,31 @@ var on = true; display.cursorDiv.style.visibility = ""; if (cm.options.cursorBlinkRate > 0) - { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; }, - cm.options.cursorBlinkRate); } + { display.blinker = setInterval(function () { + if (!cm.hasFocus()) { onBlur(cm); } + display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; + }, cm.options.cursorBlinkRate); } else if (cm.options.cursorBlinkRate < 0) { display.cursorDiv.style.visibility = "hidden"; } } function ensureFocus(cm) { - if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } + if (!cm.hasFocus()) { + cm.display.input.focus(); + if (!cm.state.focused) { onFocus(cm); } + } } function delayBlurEvent(cm) { cm.state.delayingBlurEvent = true; setTimeout(function () { if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; - onBlur(cm); + if (cm.state.focused) { onBlur(cm); } } }, 100); } function onFocus(cm, e) { - if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; } + if (cm.state.delayingBlurEvent && !cm.state.draggingText) { cm.state.delayingBlurEvent = false; } if (cm.options.readOnly == "nocursor") { return } if (!cm.state.focused) { @@ -3334,10 +3365,14 @@ function updateHeightsInViewport(cm) { var display = cm.display; var prevBottom = display.lineDiv.offsetTop; + var viewTop = Math.max(0, display.scroller.getBoundingClientRect().top); + var oldHeight = display.lineDiv.getBoundingClientRect().top; + var mustScroll = 0; for (var i = 0; i < display.view.length; i++) { var cur = display.view[i], wrapping = cm.options.lineWrapping; var height = (void 0), width = 0; if (cur.hidden) { continue } + oldHeight += cur.line.height; if (ie && ie_version < 8) { var bot = cur.node.offsetTop + cur.node.offsetHeight; height = bot - prevBottom; @@ -3352,6 +3387,7 @@ } var diff = cur.line.height - height; if (diff > .005 || diff < -.005) { + if (oldHeight < viewTop) { mustScroll -= diff; } updateLineHeight(cur.line, height); updateWidgetHeight(cur.line); if (cur.rest) { for (var j = 0; j < cur.rest.length; j++) @@ -3366,6 +3402,7 @@ } } } + if (Math.abs(mustScroll) > 2) { display.scroller.scrollTop += mustScroll; } } // Read and store the height of line widgets associated with the @@ -3409,8 +3446,9 @@ if (signalDOMEvent(cm, "scrollCursorIntoView")) { return } var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; + var doc = display.wrapper.ownerDocument; if (rect.top + box.top < 0) { doScroll = true; } - else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; } + else if (rect.bottom + box.top > (doc.defaultView.innerHeight || doc.documentElement.clientHeight)) { doScroll = false; } if (doScroll != null && !phantom) { var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;")); cm.display.lineSpace.appendChild(scrollNode); @@ -3429,8 +3467,8 @@ // Set pos and end to the cursor positions around the character pos sticks to // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch // If pos == Pos(_, 0, "before"), pos and end are unchanged - pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos; end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos; + pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos; } for (var limit = 0; limit < 5; limit++) { var changed = false; @@ -3481,14 +3519,15 @@ if (newTop != screentop) { result.scrollTop = newTop; } } - var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; - var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0); + var gutterSpace = cm.options.fixedGutter ? 0 : display.gutters.offsetWidth; + var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft - gutterSpace; + var screenw = displayWidth(cm) - display.gutters.offsetWidth; var tooWide = rect.right - rect.left > screenw; if (tooWide) { rect.right = rect.left + screenw; } if (rect.left < 10) { result.scrollLeft = 0; } else if (rect.left < screenleft) - { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); } + { result.scrollLeft = Math.max(0, rect.left + gutterSpace - (tooWide ? 0 : 10)); } else if (rect.right > screenw + screenleft - 3) { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; } return result @@ -3516,9 +3555,9 @@ if (y != null) { cm.curOp.scrollTop = y; } } - function scrollToRange(cm, range$$1) { + function scrollToRange(cm, range) { resolveScrollToPos(cm); - cm.curOp.scrollToPos = range$$1; + cm.curOp.scrollToPos = range; } // When an operation has its scrollToPos property set, and another @@ -3526,11 +3565,11 @@ // 'simulates' scrolling that position into view in a cheap way, so // that the effect of intermediate scroll commands is not ignored. function resolveScrollToPos(cm) { - var range$$1 = cm.curOp.scrollToPos; - if (range$$1) { + var range = cm.curOp.scrollToPos; + if (range) { cm.curOp.scrollToPos = null; - var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to); - scrollToCoordsRange(cm, from, to, range$$1.margin); + var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); + scrollToCoordsRange(cm, from, to, range.margin); } } @@ -3625,6 +3664,7 @@ this.vert.firstChild.style.height = Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"; } else { + this.vert.scrollTop = 0; this.vert.style.display = ""; this.vert.firstChild.style.height = "0"; } @@ -3662,13 +3702,13 @@ NativeScrollbars.prototype.zeroWidthHack = function () { var w = mac && !mac_geMountainLion ? "12px" : "18px"; this.horiz.style.height = this.vert.style.width = w; - this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"; + this.horiz.style.visibility = this.vert.style.visibility = "hidden"; this.disableHoriz = new Delayed; this.disableVert = new Delayed; }; NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) { - bar.style.pointerEvents = "auto"; + bar.style.visibility = ""; function maybeDisable() { // To find out whether the scrollbar is still visible, we // check whether the element under the pixel in the bottom @@ -3677,9 +3717,9 @@ // (when the bar is hidden). If it is still visible, we keep // it enabled, if it's hidden, we disable pointer events. var box = bar.getBoundingClientRect(); - var elt$$1 = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2) + var elt = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2) : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1); - if (elt$$1 != bar) { bar.style.pointerEvents = "none"; } + if (elt != bar) { bar.style.visibility = "hidden"; } else { delay.set(1000, maybeDisable); } } delay.set(1000, maybeDisable); @@ -3780,7 +3820,8 @@ scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet scrollToPos: null, // Used to scroll to a specific position focus: false, - id: ++nextOpId // Unique ID + id: ++nextOpId, // Unique ID + markArrays: null // Used by addMarkedSpan }; pushOperation(cm.curOp); } @@ -3859,7 +3900,7 @@ cm.display.maxLineChanged = false; } - var takeFocus = op.focus && op.focus == activeElt(); + var takeFocus = op.focus && op.focus == activeElt(doc(cm)); if (op.preparedSelection) { cm.display.input.showSelection(op.preparedSelection, takeFocus); } if (op.updatedDisplay || op.startHeight != cm.doc.height) @@ -4019,10 +4060,8 @@ { this.events.push(arguments); } }; DisplayUpdate.prototype.finish = function () { - var this$1 = this; - for (var i = 0; i < this.events.length; i++) - { signal.apply(null, this$1.events[i]); } + { signal.apply(null, this.events[i]); } }; function maybeClipScrollbars(cm) { @@ -4038,11 +4077,11 @@ function selectionSnapshot(cm) { if (cm.hasFocus()) { return null } - var active = activeElt(); + var active = activeElt(doc(cm)); if (!active || !contains(cm.display.lineDiv, active)) { return null } var result = {activeElt: active}; if (window.getSelection) { - var sel = window.getSelection(); + var sel = win(cm).getSelection(); if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) { result.anchorNode = sel.anchorNode; result.anchorOffset = sel.anchorOffset; @@ -4054,14 +4093,16 @@ } function restoreSelection(snapshot) { - if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return } + if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt(snapshot.activeElt.ownerDocument)) { return } snapshot.activeElt.focus(); - if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) { - var sel = window.getSelection(), range$$1 = document.createRange(); - range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset); - range$$1.collapse(false); + if (!/^(INPUT|TEXTAREA)$/.test(snapshot.activeElt.nodeName) && + snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) { + var doc = snapshot.activeElt.ownerDocument; + var sel = doc.defaultView.getSelection(), range = doc.createRange(); + range.setEnd(snapshot.anchorNode, snapshot.anchorOffset); + range.collapse(false); sel.removeAllRanges(); - sel.addRange(range$$1); + sel.addRange(range); sel.extend(snapshot.focusNode, snapshot.focusOffset); } } @@ -4154,6 +4195,8 @@ update.visible = visibleLines(cm.display, cm.doc, viewport); if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) { break } + } else if (first) { + update.visible = visibleLines(cm.display, cm.doc, viewport); } if (!updateDisplayIfNeeded(cm, update)) { break } updateHeightsInViewport(cm); @@ -4232,6 +4275,8 @@ function updateGutterSpace(display) { var width = display.gutters.offsetWidth; display.sizer.style.marginLeft = width + "px"; + // Send an event to consumers responding to changes in gutter width. + signalLater(display, "gutterChanged", display); } function setDocumentHeight(cm, measure) { @@ -4370,6 +4415,12 @@ d.scroller.setAttribute("tabIndex", "-1"); // The element in which the editor lives. d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); + // See #6982. FIXME remove when this has been fixed for a while in Chrome + if (chrome && chrome_version >= 105) { d.wrapper.style.clipPath = "inset(0px)"; } + + // This attribute is respected by automatic translation systems such as Google Translate, + // and may also be respected by tools used by human translators. + d.wrapper.setAttribute('translate', 'no'); // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } @@ -4467,7 +4518,24 @@ } function onScrollWheel(cm, e) { + // On Chrome 102, viewport updates somehow stop wheel-based + // scrolling. Turning off pointer events during the scroll seems + // to avoid the issue. + if (chrome && chrome_version == 102) { + if (cm.display.chromeScrollHack == null) { cm.display.sizer.style.pointerEvents = "none"; } + else { clearTimeout(cm.display.chromeScrollHack); } + cm.display.chromeScrollHack = setTimeout(function () { + cm.display.chromeScrollHack = null; + cm.display.sizer.style.pointerEvents = ""; + }, 100); + } var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y; + var pixelsPerUnit = wheelPixelsPerUnit; + if (e.deltaMode === 0) { + dx = e.deltaX; + dy = e.deltaY; + pixelsPerUnit = 1; + } var display = cm.display, scroll = display.scroller; // Quit if there's nothing to scroll here @@ -4496,10 +4564,10 @@ // estimated pixels/delta value, we just handle horizontal // scrolling entirely here. It'll be slightly off from native, but // better than glitching out. - if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { + if (dx && !gecko && !presto && pixelsPerUnit != null) { if (dy && canScrollY) - { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); } - setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit)); + { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * pixelsPerUnit)); } + setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * pixelsPerUnit)); // Only prevent default scrolling if vertical scrolling is // actually possible. Otherwise, it causes vertical scroll // jitter on OSX trackpads when deltaX is small and deltaY @@ -4512,15 +4580,15 @@ // 'Project' the visible viewport to cover the area that is being // scrolled into view (if we know enough to estimate it). - if (dy && wheelPixelsPerUnit != null) { - var pixels = dy * wheelPixelsPerUnit; + if (dy && pixelsPerUnit != null) { + var pixels = dy * pixelsPerUnit; var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; if (pixels < 0) { top = Math.max(0, top + pixels - 50); } else { bot = Math.min(cm.doc.height, bot + pixels + 50); } updateDisplaySimple(cm, {top: top, bottom: bot}); } - if (wheelSamples < 20) { + if (wheelSamples < 20 && e.deltaMode !== 0) { if (display.wheelStartX == null) { display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; display.wheelDX = dx; display.wheelDY = dy; @@ -4554,40 +4622,32 @@ Selection.prototype.primary = function () { return this.ranges[this.primIndex] }; Selection.prototype.equals = function (other) { - var this$1 = this; - if (other == this) { return true } if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false } for (var i = 0; i < this.ranges.length; i++) { - var here = this$1.ranges[i], there = other.ranges[i]; + var here = this.ranges[i], there = other.ranges[i]; if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false } } return true }; Selection.prototype.deepCopy = function () { - var this$1 = this; - var out = []; for (var i = 0; i < this.ranges.length; i++) - { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); } + { out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); } return new Selection(out, this.primIndex) }; Selection.prototype.somethingSelected = function () { - var this$1 = this; - for (var i = 0; i < this.ranges.length; i++) - { if (!this$1.ranges[i].empty()) { return true } } + { if (!this.ranges[i].empty()) { return true } } return false }; Selection.prototype.contains = function (pos, end) { - var this$1 = this; - if (!end) { end = pos; } for (var i = 0; i < this.ranges.length; i++) { - var range = this$1.ranges[i]; + var range = this.ranges[i]; if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) { return i } } @@ -4713,16 +4773,16 @@ } // Perform a change on the document data structure. - function updateDoc(doc, change, markedSpans, estimateHeight$$1) { + function updateDoc(doc, change, markedSpans, estimateHeight) { function spansFor(n) {return markedSpans ? markedSpans[n] : null} function update(line, text, spans) { - updateLine(line, text, spans, estimateHeight$$1); + updateLine(line, text, spans, estimateHeight); signalLater(line, "change", line, change); } function linesFor(start, end) { var result = []; for (var i = start; i < end; ++i) - { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); } + { result.push(new Line(text[i], spansFor(i), estimateHeight)); } return result } @@ -4746,7 +4806,7 @@ update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); } else { var added$1 = linesFor(1, text.length - 1); - added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1)); + added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); doc.insert(from.line + 1, added$1); } @@ -4787,6 +4847,7 @@ estimateLineHeights(cm); loadMode(cm); setDirectionClass(cm); + cm.options.direction = doc.direction; if (!cm.options.lineWrapping) { findMaxLine(cm); } cm.options.mode = doc.modeOption; regChange(cm); @@ -4803,19 +4864,19 @@ }); } - function History(startGen) { + function History(prev) { // Arrays of change events and selections. Doing something adds an // event to done and clears undo. Undoing moves events from done // to undone, redoing moves them in the other direction. this.done = []; this.undone = []; - this.undoDepth = Infinity; + this.undoDepth = prev ? prev.undoDepth : Infinity; // Used to track when changes can be merged into a single undo // event this.lastModTime = this.lastSelTime = 0; this.lastOp = this.lastSelOp = null; this.lastOrigin = this.lastSelOrigin = null; // Used by the isClean() method - this.generation = this.maxGeneration = startGen || 1; + this.generation = this.maxGeneration = prev ? prev.maxGeneration : 1; } // Create a history change event from an updateDoc-style change @@ -5083,11 +5144,9 @@ var obj = { ranges: sel.ranges, update: function(ranges) { - var this$1 = this; - this.ranges = []; for (var i = 0; i < ranges.length; i++) - { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), + { this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), clipPos(doc, ranges[i].head)); } }, origin: options && options.origin @@ -5122,7 +5181,7 @@ (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); - if (!(options && options.scroll === false) && doc.cm) + if (!(options && options.scroll === false) && doc.cm && doc.cm.getOption("readOnly") != "nocursor") { ensureCursorVisible(doc.cm); } } @@ -5153,7 +5212,7 @@ var range = sel.ranges[i]; var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i]; var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear); - var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear); + var newHead = range.head == range.anchor ? newAnchor : skipAtomic(doc, range.head, old && old.head, bias, mayClear); if (out || newAnchor != range.anchor || newHead != range.head) { if (!out) { out = sel.ranges.slice(0, i); } out[i] = new Range(newAnchor, newHead); @@ -5574,13 +5633,11 @@ // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html function LeafChunk(lines) { - var this$1 = this; - this.lines = lines; this.parent = null; var height = 0; for (var i = 0; i < lines.length; ++i) { - lines[i].parent = this$1; + lines[i].parent = this; height += lines[i].height; } this.height = height; @@ -5591,11 +5648,9 @@ // Remove the n lines at offset 'at'. removeInner: function(at, n) { - var this$1 = this; - for (var i = at, e = at + n; i < e; ++i) { - var line = this$1.lines[i]; - this$1.height -= line.height; + var line = this.lines[i]; + this.height -= line.height; cleanUpLine(line); signalLater(line, "delete"); } @@ -5610,31 +5665,25 @@ // Insert the given array of lines at offset 'at', count them as // having the given height. insertInner: function(at, lines, height) { - var this$1 = this; - this.height += height; this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); - for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; } + for (var i = 0; i < lines.length; ++i) { lines[i].parent = this; } }, // Used to iterate over a part of the tree. iterN: function(at, n, op) { - var this$1 = this; - for (var e = at + n; at < e; ++at) - { if (op(this$1.lines[at])) { return true } } + { if (op(this.lines[at])) { return true } } } }; function BranchChunk(children) { - var this$1 = this; - this.children = children; var size = 0, height = 0; for (var i = 0; i < children.length; ++i) { var ch = children[i]; size += ch.chunkSize(); height += ch.height; - ch.parent = this$1; + ch.parent = this; } this.size = size; this.height = height; @@ -5645,16 +5694,14 @@ chunkSize: function() { return this.size }, removeInner: function(at, n) { - var this$1 = this; - this.size -= n; for (var i = 0; i < this.children.length; ++i) { - var child = this$1.children[i], sz = child.chunkSize(); + var child = this.children[i], sz = child.chunkSize(); if (at < sz) { var rm = Math.min(n, sz - at), oldHeight = child.height; child.removeInner(at, rm); - this$1.height -= oldHeight - child.height; - if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; } + this.height -= oldHeight - child.height; + if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } if ((n -= rm) == 0) { break } at = 0; } else { at -= sz; } @@ -5671,18 +5718,14 @@ }, collapse: function(lines) { - var this$1 = this; - - for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); } + for (var i = 0; i < this.children.length; ++i) { this.children[i].collapse(lines); } }, insertInner: function(at, lines, height) { - var this$1 = this; - this.size += lines.length; this.height += height; for (var i = 0; i < this.children.length; ++i) { - var child = this$1.children[i], sz = child.chunkSize(); + var child = this.children[i], sz = child.chunkSize(); if (at <= sz) { child.insertInner(at, lines, height); if (child.lines && child.lines.length > 50) { @@ -5692,11 +5735,11 @@ for (var pos = remaining; pos < child.lines.length;) { var leaf = new LeafChunk(child.lines.slice(pos, pos += 25)); child.height -= leaf.height; - this$1.children.splice(++i, 0, leaf); - leaf.parent = this$1; + this.children.splice(++i, 0, leaf); + leaf.parent = this; } child.lines = child.lines.slice(0, remaining); - this$1.maybeSpill(); + this.maybeSpill(); } break } @@ -5728,10 +5771,8 @@ }, iterN: function(at, n, op) { - var this$1 = this; - for (var i = 0; i < this.children.length; ++i) { - var child = this$1.children[i], sz = child.chunkSize(); + var child = this.children[i], sz = child.chunkSize(); if (at < sz) { var used = Math.min(n, sz - at); if (child.iterN(at, used, op)) { return true } @@ -5745,20 +5786,16 @@ // Line widgets are block elements displayed above or below a line. var LineWidget = function(doc, node, options) { - var this$1 = this; - if (options) { for (var opt in options) { if (options.hasOwnProperty(opt)) - { this$1[opt] = options[opt]; } } } + { this[opt] = options[opt]; } } } this.doc = doc; this.node = node; }; LineWidget.prototype.clear = function () { - var this$1 = this; - var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); if (no == null || !ws) { return } - for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } } + for (var i = 0; i < ws.length; ++i) { if (ws[i] == this) { ws.splice(i--, 1); } } if (!ws.length) { line.widgets = null; } var height = widgetHeight(this); updateLineHeight(line, Math.max(0, line.height - height)); @@ -5801,7 +5838,7 @@ changeLine(doc, handle, "widget", function (line) { var widgets = line.widgets || (line.widgets = []); if (widget.insertAt == null) { widgets.push(widget); } - else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); } + else { widgets.splice(Math.min(widgets.length, Math.max(0, widget.insertAt)), 0, widget); } widget.line = line; if (cm && !lineIsHidden(doc, line)) { var aboveVisible = heightAtLine(line) < doc.scrollTop; @@ -5841,8 +5878,6 @@ // Clear the marker. TextMarker.prototype.clear = function () { - var this$1 = this; - if (this.explicitlyCleared) { return } var cm = this.doc.cm, withOp = cm && !cm.curOp; if (withOp) { startOperation(cm); } @@ -5852,19 +5887,19 @@ } var min = null, max = null; for (var i = 0; i < this.lines.length; ++i) { - var line = this$1.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this$1); - if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text"); } + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (cm && !this.collapsed) { regLineChange(cm, lineNo(line), "text"); } else if (cm) { if (span.to != null) { max = lineNo(line); } if (span.from != null) { min = lineNo(line); } } line.markedSpans = removeMarkedSpan(line.markedSpans, span); - if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm) + if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) { updateLineHeight(line, textHeight(cm.display)); } } if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) { - var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual); + var visual = visualLine(this.lines[i$1]), len = lineLength(visual); if (len > cm.display.maxLineLength) { cm.display.maxLine = visual; cm.display.maxLineLength = len; @@ -5890,13 +5925,11 @@ // Pos objects returned contain a line object, rather than a line // number (used to prevent looking up the same line twice). TextMarker.prototype.find = function (side, lineObj) { - var this$1 = this; - if (side == null && this.type == "bookmark") { side = 1; } var from, to; for (var i = 0; i < this.lines.length; ++i) { - var line = this$1.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this$1); + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); if (span.from != null) { from = Pos(lineObj ? line : lineNo(line), span.from); if (side == -1) { return from } @@ -5991,7 +6024,7 @@ if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); } addMarkedSpan(line, new MarkedSpan(marker, curLine == from.line ? from.ch : null, - curLine == to.line ? to.ch : null)); + curLine == to.line ? to.ch : null), doc.cm && doc.cm.curOp); ++curLine; }); // lineIsHidden depends on the presence of the spans, so needs a second pass @@ -6030,21 +6063,17 @@ // implemented as a meta-marker-object controlling multiple normal // markers. var SharedTextMarker = function(markers, primary) { - var this$1 = this; - this.markers = markers; this.primary = primary; for (var i = 0; i < markers.length; ++i) - { markers[i].parent = this$1; } + { markers[i].parent = this; } }; SharedTextMarker.prototype.clear = function () { - var this$1 = this; - if (this.explicitlyCleared) { return } this.explicitlyCleared = true; for (var i = 0; i < this.markers.length; ++i) - { this$1.markers[i].clear(); } + { this.markers[i].clear(); } signalLater(this, "clear"); }; @@ -6167,6 +6196,7 @@ getRange: function(from, to, lineSep) { var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); if (lineSep === false) { return lines } + if (lineSep === '') { return lines.join('') } return lines.join(lineSep || this.lineSeparator()) }, @@ -6187,11 +6217,11 @@ clipPos: function(pos) {return clipPos(this, pos)}, getCursor: function(start) { - var range$$1 = this.sel.primary(), pos; - if (start == null || start == "head") { pos = range$$1.head; } - else if (start == "anchor") { pos = range$$1.anchor; } - else if (start == "end" || start == "to" || start === false) { pos = range$$1.to(); } - else { pos = range$$1.from(); } + var range = this.sel.primary(), pos; + if (start == null || start == "head") { pos = range.head; } + else if (start == "anchor") { pos = range.anchor; } + else if (start == "end" || start == "to" || start === false) { pos = range.to(); } + else { pos = range.from(); } return pos }, listSelections: function() { return this.sel.ranges }, @@ -6214,13 +6244,11 @@ extendSelections(this, clipPosArray(this, heads), options); }), setSelections: docMethodOp(function(ranges, primary, options) { - var this$1 = this; - if (!ranges.length) { return } var out = []; for (var i = 0; i < ranges.length; i++) - { out[i] = new Range(clipPos(this$1, ranges[i].anchor), - clipPos(this$1, ranges[i].head)); } + { out[i] = new Range(clipPos(this, ranges[i].anchor), + clipPos(this, ranges[i].head || ranges[i].anchor)); } if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); } setSelection(this, normalizeSelection(this.cm, out, primary), options); }), @@ -6231,23 +6259,19 @@ }), getSelection: function(lineSep) { - var this$1 = this; - var ranges = this.sel.ranges, lines; for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()); + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); lines = lines ? lines.concat(sel) : sel; } if (lineSep === false) { return lines } else { return lines.join(lineSep || this.lineSeparator()) } }, getSelections: function(lineSep) { - var this$1 = this; - var parts = [], ranges = this.sel.ranges; for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()); - if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); } + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + if (lineSep !== false) { sel = sel.join(lineSep || this.lineSeparator()); } parts[i] = sel; } return parts @@ -6259,16 +6283,14 @@ this.replaceSelections(dup, collapse, origin || "+input"); }, replaceSelections: docMethodOp(function(code, collapse, origin) { - var this$1 = this; - var changes = [], sel = this.sel; for (var i = 0; i < sel.ranges.length; i++) { - var range$$1 = sel.ranges[i]; - changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin}; + var range = sel.ranges[i]; + changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin}; } var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); for (var i$1 = changes.length - 1; i$1 >= 0; i$1--) - { makeChange(this$1, changes[i$1]); } + { makeChange(this, changes[i$1]); } if (newSel) { setSelectionReplaceHistory(this, newSel); } else if (this.cm) { ensureCursorVisible(this.cm); } }), @@ -6289,7 +6311,7 @@ clearHistory: function() { var this$1 = this; - this.history = new History(this.history.maxGeneration); + this.history = new History(this.history); linkedDocs(this, function (doc) { return doc.history = this$1.history; }, true); }, @@ -6310,7 +6332,7 @@ undone: copyHistoryArray(this.history.undone)} }, setHistory: function(histData) { - var hist = this.history = new History(this.history.maxGeneration); + var hist = this.history = new History(this.history); hist.done = copyHistoryArray(histData.done.slice(0), null, true); hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); }, @@ -6412,18 +6434,18 @@ }, findMarks: function(from, to, filter) { from = clipPos(this, from); to = clipPos(this, to); - var found = [], lineNo$$1 = from.line; + var found = [], lineNo = from.line; this.iter(from.line, to.line + 1, function (line) { var spans = line.markedSpans; if (spans) { for (var i = 0; i < spans.length; i++) { var span = spans[i]; - if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to || - span.from == null && lineNo$$1 != from.line || - span.from != null && lineNo$$1 == to.line && span.from >= to.ch) && + if (!(span.to != null && lineNo == from.line && from.ch >= span.to || + span.from == null && lineNo != from.line || + span.from != null && lineNo == to.line && span.from >= to.ch) && (!filter || filter(span.marker))) { found.push(span.marker.parent || span.marker); } } } - ++lineNo$$1; + ++lineNo; }); return found }, @@ -6438,14 +6460,14 @@ }, posFromIndex: function(off) { - var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length; + var ch, lineNo = this.first, sepSize = this.lineSeparator().length; this.iter(function (line) { var sz = line.text.length + sepSize; if (sz > off) { ch = off; return true } off -= sz; - ++lineNo$$1; + ++lineNo; }); - return clipPos(this, Pos(lineNo$$1, ch)) + return clipPos(this, Pos(lineNo, ch)) }, indexFromPos: function (coords) { coords = clipPos(this, coords); @@ -6484,15 +6506,13 @@ return copy }, unlinkDoc: function(other) { - var this$1 = this; - if (other instanceof CodeMirror) { other = other.doc; } if (this.linked) { for (var i = 0; i < this.linked.length; ++i) { - var link = this$1.linked[i]; + var link = this.linked[i]; if (link.doc != other) { continue } - this$1.linked.splice(i, 1); - other.unlinkDoc(this$1); - detachSharedMarkers(findSharedMarkers(this$1)); + this.linked.splice(i, 1); + other.unlinkDoc(this); + detachSharedMarkers(findSharedMarkers(this)); break } } // If the histories were shared, split them again @@ -6598,7 +6618,7 @@ cm.display.input.focus(); } } - catch(e){} + catch(e$1){} } } @@ -6694,7 +6714,7 @@ 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 145: "ScrollLock", 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", - 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", + 221: "]", 222: "'", 224: "Mod", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" }; @@ -6731,10 +6751,9 @@ // Very basic readline/emacs-style bindings, which are standard on Mac. keyMap.emacsy = { "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", - "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", - "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", - "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars", - "Ctrl-O": "openLine" + "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", + "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", + "Ctrl-T": "transposeChars", "Ctrl-O": "openLine" }; keyMap.macDefault = { "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", @@ -6801,18 +6820,18 @@ return keymap } - function lookupKey(key, map$$1, handle, context) { - map$$1 = getKeyMap(map$$1); - var found = map$$1.call ? map$$1.call(key, context) : map$$1[key]; + function lookupKey(key, map, handle, context) { + map = getKeyMap(map); + var found = map.call ? map.call(key, context) : map[key]; if (found === false) { return "nothing" } if (found === "...") { return "multi" } if (found != null && handle(found)) { return "handled" } - if (map$$1.fallthrough) { - if (Object.prototype.toString.call(map$$1.fallthrough) != "[object Array]") - { return lookupKey(key, map$$1.fallthrough, handle, context) } - for (var i = 0; i < map$$1.fallthrough.length; i++) { - var result = lookupKey(key, map$$1.fallthrough[i], handle, context); + if (map.fallthrough) { + if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") + { return lookupKey(key, map.fallthrough, handle, context) } + for (var i = 0; i < map.fallthrough.length; i++) { + var result = lookupKey(key, map.fallthrough[i], handle, context); if (result) { return result } } } @@ -6829,7 +6848,7 @@ var base = name; if (event.altKey && base != "Alt") { name = "Alt-" + name; } if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; } - if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; } + if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Mod") { name = "Cmd-" + name; } if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; } return name } @@ -7055,7 +7074,7 @@ goGroupRight: function (cm) { return cm.moveH(1, "group"); }, goGroupLeft: function (cm) { return cm.moveH(-1, "group"); }, goWordRight: function (cm) { return cm.moveH(1, "word"); }, - delCharBefore: function (cm) { return cm.deleteH(-1, "char"); }, + delCharBefore: function (cm) { return cm.deleteH(-1, "codepoint"); }, delCharAfter: function (cm) { return cm.deleteH(1, "char"); }, delWordBefore: function (cm) { return cm.deleteH(-1, "word"); }, delWordAfter: function (cm) { return cm.deleteH(1, "word"); }, @@ -7244,7 +7263,8 @@ var lastStoppedKey = null; function onKeyDown(e) { var cm = this; - cm.curOp.focus = activeElt(); + if (e.target && e.target != cm.display.input.getField()) { return } + cm.curOp.focus = activeElt(doc(cm)); if (signalDOMEvent(cm, e)) { return } // IE does strange things with escape. if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; } @@ -7287,6 +7307,7 @@ function onKeyPress(e) { var cm = this; + if (e.target && e.target != cm.display.input.getField()) { return } if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return } var keyCode = e.keyCode, charCode = e.charCode; if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return} @@ -7350,7 +7371,7 @@ } if (clickInGutter(cm, e)) { return } var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single"; - window.focus(); + win(cm).focus(); // #3261: make sure, that we're not starting a second selection if (button == 1 && cm.state.selectingText) @@ -7405,7 +7426,7 @@ function leftButtonDown(cm, pos, repeat, event) { if (ie) { setTimeout(bind(ensureFocus, cm), 0); } - else { cm.curOp.focus = activeElt(); } + else { cm.curOp.focus = activeElt(doc(cm)); } var behavior = configureMouse(cm, repeat, event); @@ -7426,6 +7447,10 @@ var dragEnd = operation(cm, function (e) { if (webkit) { display.scroller.draggable = false; } cm.state.draggingText = false; + if (cm.state.delayingBlurEvent) { + if (cm.hasFocus()) { cm.state.delayingBlurEvent = false; } + else { delayBlurEvent(cm); } + } off(display.wrapper.ownerDocument, "mouseup", dragEnd); off(display.wrapper.ownerDocument, "mousemove", mouseMove); off(display.scroller, "dragstart", dragStart); @@ -7435,8 +7460,8 @@ if (!behavior.addNew) { extendSelection(cm.doc, pos, null, null, behavior.extend); } // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) - if (webkit || ie && ie_version == 9) - { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus();}, 20); } + if ((webkit && !safari) || ie && ie_version == 9) + { setTimeout(function () {display.wrapper.ownerDocument.body.focus({preventScroll: true}); display.input.focus();}, 20); } else { display.input.focus(); } } @@ -7449,15 +7474,15 @@ if (webkit) { display.scroller.draggable = true; } cm.state.draggingText = dragEnd; dragEnd.copy = !behavior.moveOnDrag; - // IE's approach to draggable - if (display.scroller.dragDrop) { display.scroller.dragDrop(); } on(display.wrapper.ownerDocument, "mouseup", dragEnd); on(display.wrapper.ownerDocument, "mousemove", mouseMove); on(display.scroller, "dragstart", dragStart); on(display.scroller, "drop", dragEnd); - delayBlurEvent(cm); + cm.state.delayingBlurEvent = true; setTimeout(function () { return display.input.focus(); }, 20); + // IE's approach to draggable + if (display.scroller.dragDrop) { display.scroller.dragDrop(); } } function rangeForUnit(cm, pos, unit) { @@ -7470,19 +7495,20 @@ // Normal selection, as opposed to text dragging. function leftButtonSelect(cm, event, start, behavior) { - var display = cm.display, doc = cm.doc; + if (ie) { delayBlurEvent(cm); } + var display = cm.display, doc$1 = cm.doc; e_preventDefault(event); - var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges; + var ourRange, ourIndex, startSel = doc$1.sel, ranges = startSel.ranges; if (behavior.addNew && !behavior.extend) { - ourIndex = doc.sel.contains(start); + ourIndex = doc$1.sel.contains(start); if (ourIndex > -1) { ourRange = ranges[ourIndex]; } else { ourRange = new Range(start, start); } } else { - ourRange = doc.sel.primary(); - ourIndex = doc.sel.primIndex; + ourRange = doc$1.sel.primary(); + ourIndex = doc$1.sel.primIndex; } if (behavior.unit == "rectangle") { @@ -7490,27 +7516,27 @@ start = posFromMouse(cm, event, true, true); ourIndex = -1; } else { - var range$$1 = rangeForUnit(cm, start, behavior.unit); + var range = rangeForUnit(cm, start, behavior.unit); if (behavior.extend) - { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); } + { ourRange = extendRange(ourRange, range.anchor, range.head, behavior.extend); } else - { ourRange = range$$1; } + { ourRange = range; } } if (!behavior.addNew) { ourIndex = 0; - setSelection(doc, new Selection([ourRange], 0), sel_mouse); - startSel = doc.sel; + setSelection(doc$1, new Selection([ourRange], 0), sel_mouse); + startSel = doc$1.sel; } else if (ourIndex == -1) { ourIndex = ranges.length; - setSelection(doc, normalizeSelection(cm, ranges.concat([ourRange]), ourIndex), + setSelection(doc$1, normalizeSelection(cm, ranges.concat([ourRange]), ourIndex), {scroll: false, origin: "*mouse"}); } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) { - setSelection(doc, normalizeSelection(cm, ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0), + setSelection(doc$1, normalizeSelection(cm, ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0), {scroll: false, origin: "*mouse"}); - startSel = doc.sel; + startSel = doc$1.sel; } else { - replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); + replaceOneSelection(doc$1, ourIndex, ourRange, sel_mouse); } var lastPos = start; @@ -7520,35 +7546,35 @@ if (behavior.unit == "rectangle") { var ranges = [], tabSize = cm.options.tabSize; - var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); - var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); + var startCol = countColumn(getLine(doc$1, start.line).text, start.ch, tabSize); + var posCol = countColumn(getLine(doc$1, pos.line).text, pos.ch, tabSize); var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); line <= end; line++) { - var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); + var text = getLine(doc$1, line).text, leftPos = findColumn(text, left, tabSize); if (left == right) { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); } else if (text.length > leftPos) { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); } } if (!ranges.length) { ranges.push(new Range(start, start)); } - setSelection(doc, normalizeSelection(cm, startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), + setSelection(doc$1, normalizeSelection(cm, startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), {origin: "*mouse", scroll: false}); cm.scrollIntoView(pos); } else { var oldRange = ourRange; - var range$$1 = rangeForUnit(cm, pos, behavior.unit); + var range = rangeForUnit(cm, pos, behavior.unit); var anchor = oldRange.anchor, head; - if (cmp(range$$1.anchor, anchor) > 0) { - head = range$$1.head; - anchor = minPos(oldRange.from(), range$$1.anchor); + if (cmp(range.anchor, anchor) > 0) { + head = range.head; + anchor = minPos(oldRange.from(), range.anchor); } else { - head = range$$1.anchor; - anchor = maxPos(oldRange.to(), range$$1.head); + head = range.anchor; + anchor = maxPos(oldRange.to(), range.head); } var ranges$1 = startSel.ranges.slice(0); - ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head)); - setSelection(doc, normalizeSelection(cm, ranges$1, ourIndex), sel_mouse); + ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc$1, anchor), head)); + setSelection(doc$1, normalizeSelection(cm, ranges$1, ourIndex), sel_mouse); } } @@ -7564,9 +7590,9 @@ var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle"); if (!cur) { return } if (cmp(cur, lastPos) != 0) { - cm.curOp.focus = activeElt(); + cm.curOp.focus = activeElt(doc(cm)); extendTo(cur); - var visible = visibleLines(display, doc); + var visible = visibleLines(display, doc$1); if (cur.line >= visible.to || cur.line < visible.from) { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); } } else { @@ -7591,7 +7617,7 @@ } off(display.wrapper.ownerDocument, "mousemove", move); off(display.wrapper.ownerDocument, "mouseup", up); - doc.history.lastSelOrigin = null; + doc$1.history.lastSelOrigin = null; } var move = operation(cm, function (e) { @@ -7606,17 +7632,17 @@ // Used when mouse-selecting to adjust the anchor to the proper side // of a bidi jump depending on the visual position of the head. - function bidiSimplify(cm, range$$1) { - var anchor = range$$1.anchor; - var head = range$$1.head; + function bidiSimplify(cm, range) { + var anchor = range.anchor; + var head = range.head; var anchorLine = getLine(cm.doc, anchor.line); - if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range$$1 } + if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range } var order = getOrder(anchorLine); - if (!order) { return range$$1 } + if (!order) { return range } var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index]; - if (part.from != anchor.ch && part.to != anchor.ch) { return range$$1 } + if (part.from != anchor.ch && part.to != anchor.ch) { return range } var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1); - if (boundary == 0 || boundary == order.length) { return range$$1 } + if (boundary == 0 || boundary == order.length) { return range } // Compute the relative visual position of the head compared to the // anchor (<0 is to the left, >0 to the right) @@ -7635,7 +7661,7 @@ var usePart = order[boundary + (leftSide ? -1 : 0)]; var from = leftSide == (usePart.level == 1); var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before"; - return anchor.ch == ch && anchor.sticky == sticky ? range$$1 : new Range(new Pos(anchor.line, ch, sticky), head) + return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head) } @@ -7648,7 +7674,7 @@ mY = e.touches[0].clientY; } else { try { mX = e.clientX; mY = e.clientY; } - catch(e) { return false } + catch(e$1) { return false } } if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false } if (prevent) { e_preventDefault(e); } @@ -7748,7 +7774,7 @@ for (var i = newBreaks.length - 1; i >= 0; i--) { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); } }); - option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g, function (cm, val, old) { + option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\u2066\u2067\u2069\ufeff\ufff9-\ufffc]/g, function (cm, val, old) { cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); if (old != Init) { cm.refresh(); } }); @@ -7812,6 +7838,12 @@ } cm.display.input.readOnlyChanged(val); }); + + option("screenReaderLabel", null, function (cm, val) { + val = (val === '') ? null : val; + cm.display.input.screenReaderLabelChanged(val); + }); + option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true); option("dragDrop", true, dragDropChanged); option("allowDropFileTypes", null); @@ -7922,15 +7954,17 @@ attachDoc(this, doc); if ((options.autofocus && !mobile) || this.hasFocus()) - { setTimeout(bind(onFocus, this), 20); } + { setTimeout(function () { + if (this$1.hasFocus() && !this$1.state.focused) { onFocus(this$1); } + }, 20); } else { onBlur(this); } for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt)) - { optionHandlers[opt](this$1, options[opt], Init); } } + { optionHandlers[opt](this, options[opt], Init); } } maybeUpdateLineNumberWidth(this); if (options.finishInit) { options.finishInit(this); } - for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); } + for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this); } endOperation(this); // Suppress optimizelegibility in Webkit, since it breaks text // measuring on line wrapping boundaries. @@ -8155,14 +8189,14 @@ var updateInput = cm.curOp.updateInput; // Normal behavior is to insert the new text into every selection for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) { - var range$$1 = sel.ranges[i$1]; - var from = range$$1.from(), to = range$$1.to(); - if (range$$1.empty()) { + var range = sel.ranges[i$1]; + var from = range.from(), to = range.to(); + if (range.empty()) { if (deleted && deleted > 0) // Handle deletion { from = Pos(from.line, from.ch - deleted); } else if (cm.state.overwrite && !paste) // Handle overwrite { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); } - else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted) + else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == textLines.join("\n")) { from = to = Pos(from.line, 0); } } var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines, @@ -8183,7 +8217,7 @@ var pasted = e.clipboardData && e.clipboardData.getData("Text"); if (pasted) { e.preventDefault(); - if (!cm.isReadOnly() && !cm.options.disableInput) + if (!cm.isReadOnly() && !cm.options.disableInput && cm.hasFocus()) { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }); } return true } @@ -8195,21 +8229,21 @@ var sel = cm.doc.sel; for (var i = sel.ranges.length - 1; i >= 0; i--) { - var range$$1 = sel.ranges[i]; - if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue } - var mode = cm.getModeAt(range$$1.head); + var range = sel.ranges[i]; + if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) { continue } + var mode = cm.getModeAt(range.head); var indented = false; if (mode.electricChars) { for (var j = 0; j < mode.electricChars.length; j++) { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { - indented = indentLine(cm, range$$1.head.line, "smart"); + indented = indentLine(cm, range.head.line, "smart"); break } } } else if (mode.electricInput) { - if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch))) - { indented = indentLine(cm, range$$1.head.line, "smart"); } + if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) + { indented = indentLine(cm, range.head.line, "smart"); } } - if (indented) { signalLater(cm, "electricInput", cm, range$$1.head.line); } + if (indented) { signalLater(cm, "electricInput", cm, range.head.line); } } } @@ -8231,7 +8265,7 @@ } function hiddenTextarea() { - var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none"); + var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; min-height: 1em; outline: none"); var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); // The textarea is kept positioned near the cursor to prevent the // fact that it'll be scrolled into view on input from scrolling @@ -8260,7 +8294,7 @@ CodeMirror.prototype = { constructor: CodeMirror, - focus: function(){window.focus(); this.display.input.focus();}, + focus: function(){win(this).focus(); this.display.input.focus();}, setOption: function(option, value) { var options = this.options, old = options[option]; @@ -8274,13 +8308,13 @@ getOption: function(option) {return this.options[option]}, getDoc: function() {return this.doc}, - addKeyMap: function(map$$1, bottom) { - this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map$$1)); + addKeyMap: function(map, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); }, - removeKeyMap: function(map$$1) { + removeKeyMap: function(map) { var maps = this.state.keyMaps; for (var i = 0; i < maps.length; ++i) - { if (maps[i] == map$$1 || maps[i].name == map$$1) { + { if (maps[i] == map || maps[i].name == map) { maps.splice(i, 1); return true } } @@ -8297,15 +8331,13 @@ regChange(this); }), removeOverlay: methodOp(function(spec) { - var this$1 = this; - var overlays = this.state.overlays; for (var i = 0; i < overlays.length; ++i) { var cur = overlays[i].modeSpec; if (cur == spec || typeof spec == "string" && cur.name == spec) { overlays.splice(i, 1); - this$1.state.modeGen++; - regChange(this$1); + this.state.modeGen++; + regChange(this); return } } @@ -8319,24 +8351,22 @@ if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); } }), indentSelection: methodOp(function(how) { - var this$1 = this; - var ranges = this.doc.sel.ranges, end = -1; for (var i = 0; i < ranges.length; i++) { - var range$$1 = ranges[i]; - if (!range$$1.empty()) { - var from = range$$1.from(), to = range$$1.to(); + var range = ranges[i]; + if (!range.empty()) { + var from = range.from(), to = range.to(); var start = Math.max(end, from.line); - end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; + end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; for (var j = start; j < end; ++j) - { indentLine(this$1, j, how); } - var newRanges = this$1.doc.sel.ranges; + { indentLine(this, j, how); } + var newRanges = this.doc.sel.ranges; if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) - { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); } - } else if (range$$1.head.line > end) { - indentLine(this$1, range$$1.head.line, how, true); - end = range$$1.head.line; - if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); } + { replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); } + } else if (range.head.line > end) { + indentLine(this, range.head.line, how, true); + end = range.head.line; + if (i == this.doc.sel.primIndex) { ensureCursorVisible(this); } } } }), @@ -8378,8 +8408,6 @@ }, getHelpers: function(pos, type) { - var this$1 = this; - var found = []; if (!helpers.hasOwnProperty(type)) { return found } var help = helpers[type], mode = this.getModeAt(pos); @@ -8397,7 +8425,7 @@ } for (var i$1 = 0; i$1 < help._global.length; i$1++) { var cur = help._global[i$1]; - if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1) + if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) { found.push(cur.val); } } return found @@ -8410,10 +8438,10 @@ }, cursorCoords: function(start, mode) { - var pos, range$$1 = this.doc.sel.primary(); - if (start == null) { pos = range$$1.head; } + var pos, range = this.doc.sel.primary(); + if (start == null) { pos = range.head; } else if (typeof start == "object") { pos = clipPos(this.doc, start); } - else { pos = start ? range$$1.from() : range$$1.to(); } + else { pos = start ? range.from() : range.to(); } return cursorCoords(this, pos, mode || "page") }, @@ -8497,13 +8525,11 @@ triggerElectric: methodOp(function(text) { triggerElectric(this, text); }), findPosH: function(from, amount, unit, visually) { - var this$1 = this; - var dir = 1; if (amount < 0) { dir = -1; amount = -amount; } var cur = clipPos(this.doc, from); for (var i = 0; i < amount; ++i) { - cur = findPosH(this$1.doc, cur, dir, unit, visually); + cur = findPosH(this.doc, cur, dir, unit, visually); if (cur.hitSide) { break } } return cur @@ -8512,11 +8538,11 @@ moveH: methodOp(function(dir, unit) { var this$1 = this; - this.extendSelectionsBy(function (range$$1) { - if (this$1.display.shift || this$1.doc.extend || range$$1.empty()) - { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) } + this.extendSelectionsBy(function (range) { + if (this$1.display.shift || this$1.doc.extend || range.empty()) + { return findPosH(this$1.doc, range.head, dir, unit, this$1.options.rtlMoveVisually) } else - { return dir < 0 ? range$$1.from() : range$$1.to() } + { return dir < 0 ? range.from() : range.to() } }, sel_move); }), @@ -8525,23 +8551,21 @@ if (sel.somethingSelected()) { doc.replaceSelection("", null, "+delete"); } else - { deleteNearSelection(this, function (range$$1) { - var other = findPosH(doc, range$$1.head, dir, unit, false); - return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other} + { deleteNearSelection(this, function (range) { + var other = findPosH(doc, range.head, dir, unit, false); + return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other} }); } }), findPosV: function(from, amount, unit, goalColumn) { - var this$1 = this; - var dir = 1, x = goalColumn; if (amount < 0) { dir = -1; amount = -amount; } var cur = clipPos(this.doc, from); for (var i = 0; i < amount; ++i) { - var coords = cursorCoords(this$1, cur, "div"); + var coords = cursorCoords(this, cur, "div"); if (x == null) { x = coords.left; } else { coords.left = x; } - cur = findPosV(this$1, coords, dir, unit); + cur = findPosV(this, coords, dir, unit); if (cur.hitSide) { break } } return cur @@ -8552,14 +8576,14 @@ var doc = this.doc, goals = []; var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected(); - doc.extendSelectionsBy(function (range$$1) { + doc.extendSelectionsBy(function (range) { if (collapse) - { return dir < 0 ? range$$1.from() : range$$1.to() } - var headPos = cursorCoords(this$1, range$$1.head, "div"); - if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; } + { return dir < 0 ? range.from() : range.to() } + var headPos = cursorCoords(this$1, range.head, "div"); + if (range.goalColumn != null) { headPos.left = range.goalColumn; } goals.push(headPos.left); var pos = findPosV(this$1, headPos, dir, unit); - if (unit == "page" && range$$1 == doc.sel.primary()) + if (unit == "page" && range == doc.sel.primary()) { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); } return pos }, sel_move); @@ -8594,7 +8618,7 @@ signal(this, "overwriteToggle", this, this.state.overwrite); }, - hasFocus: function() { return this.display.input.getField() == activeElt() }, + hasFocus: function() { return this.display.input.getField() == activeElt(doc(this)) }, isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) }, scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }), @@ -8606,22 +8630,22 @@ clientHeight: displayHeight(this), clientWidth: displayWidth(this)} }, - scrollIntoView: methodOp(function(range$$1, margin) { - if (range$$1 == null) { - range$$1 = {from: this.doc.sel.primary().head, to: null}; + scrollIntoView: methodOp(function(range, margin) { + if (range == null) { + range = {from: this.doc.sel.primary().head, to: null}; if (margin == null) { margin = this.options.cursorScrollMargin; } - } else if (typeof range$$1 == "number") { - range$$1 = {from: Pos(range$$1, 0), to: null}; - } else if (range$$1.from == null) { - range$$1 = {from: range$$1, to: null}; + } else if (typeof range == "number") { + range = {from: Pos(range, 0), to: null}; + } else if (range.from == null) { + range = {from: range, to: null}; } - if (!range$$1.to) { range$$1.to = range$$1.from; } - range$$1.margin = margin || 0; + if (!range.to) { range.to = range.from; } + range.margin = margin || 0; - if (range$$1.from.line != null) { - scrollToRange(this, range$$1); + if (range.from.line != null) { + scrollToRange(this, range); } else { - scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin); + scrollToCoordsRange(this, range.from, range.to, range.margin); } }), @@ -8632,11 +8656,11 @@ if (width != null) { this.display.wrapper.style.width = interpret(width); } if (height != null) { this.display.wrapper.style.height = interpret(height); } if (this.options.lineWrapping) { clearLineMeasurementCache(this); } - var lineNo$$1 = this.display.viewFrom; - this.doc.iter(lineNo$$1, this.display.viewTo, function (line) { + var lineNo = this.display.viewFrom; + this.doc.iter(lineNo, this.display.viewTo, function (line) { if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) - { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, "widget"); break } } } - ++lineNo$$1; + { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo, "widget"); break } } } + ++lineNo; }); this.curOp.forceUpdate = true; signal(this, "refresh", this); @@ -8653,7 +8677,7 @@ clearCaches(this); scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop); updateGutterSpace(this.display); - if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) + if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5 || this.options.lineWrapping) { estimateLineHeights(this); } signal(this, "refresh", this); }), @@ -8695,14 +8719,14 @@ } // Used for horizontal relative motion. Dir is -1 or 1 (left or - // right), unit can be "char", "column" (like char, but doesn't - // cross line boundaries), "word" (across next word), or "group" (to - // the start of next group of word or non-word-non-whitespace - // chars). The visually param controls whether, in right-to-left - // text, direction 1 means to move towards the next index in the - // string, or towards the character to the right of the current - // position. The resulting position will have a hitSide=true - // property if it reached the end of the document. + // right), unit can be "codepoint", "char", "column" (like char, but + // doesn't cross line boundaries), "word" (across next word), or + // "group" (to the start of next group of word or + // non-word-non-whitespace chars). The visually param controls + // whether, in right-to-left text, direction 1 means to move towards + // the next index in the string, or towards the character to the right + // of the current position. The resulting position will have a + // hitSide=true property if it reached the end of the document. function findPosH(doc, pos, dir, unit, visually) { var oldPos = pos; var origDir = dir; @@ -8716,7 +8740,15 @@ } function moveOnce(boundToLine) { var next; - if (visually) { + if (unit == "codepoint") { + var ch = lineObj.text.charCodeAt(pos.ch + (dir > 0 ? 0 : -1)); + if (isNaN(ch)) { + next = null; + } else { + var astral = dir > 0 ? ch >= 0xD800 && ch < 0xDC00 : ch >= 0xDC00 && ch < 0xDFFF; + next = new Pos(pos.line, Math.max(0, Math.min(lineObj.text.length, pos.ch + dir * (astral ? 2 : 1))), -dir); + } + } else if (visually) { next = moveVisually(doc.cm, lineObj, pos, dir); } else { next = moveLogically(lineObj, pos, dir); @@ -8732,7 +8764,7 @@ return true } - if (unit == "char") { + if (unit == "char" || unit == "codepoint") { moveOnce(); } else if (unit == "column") { moveOnce(true); @@ -8767,7 +8799,7 @@ function findPosV(cm, pos, dir, unit) { var doc = cm.doc, x = pos.left, y; if (unit == "page") { - var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); + var pageSize = Math.min(cm.display.wrapper.clientHeight, win(cm).innerHeight || doc(cm).documentElement.clientHeight); var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3); y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount; @@ -8800,10 +8832,19 @@ var input = this, cm = input.cm; var div = input.div = display.lineDiv; + div.contentEditable = true; disableBrowserMagic(div, cm.options.spellcheck, cm.options.autocorrect, cm.options.autocapitalize); + function belongsToInput(e) { + for (var t = e.target; t; t = t.parentNode) { + if (t == div) { return true } + if (/\bCodeMirror-(?:line)?widget\b/.test(t.className)) { break } + } + return false + } + on(div, "paste", function (e) { - if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } + if (!belongsToInput(e) || signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } // IE doesn't fire input events, so we schedule a read for the pasted content in this way if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); } }); @@ -8828,7 +8869,7 @@ }); function onCopyCut(e) { - if (signalDOMEvent(cm, e)) { return } + if (!belongsToInput(e) || signalDOMEvent(cm, e)) { return } if (cm.somethingSelected()) { setLastCopied({lineWise: false, text: cm.getSelections()}); if (e.type == "cut") { cm.replaceSelection("", null, "cut"); } @@ -8858,7 +8899,7 @@ var kludge = hiddenTextarea(), te = kludge.firstChild; cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild); te.value = lastCopied.text.join("\n"); - var hadFocus = document.activeElement; + var hadFocus = activeElt(div.ownerDocument); selectInput(te); setTimeout(function () { cm.display.lineSpace.removeChild(kludge); @@ -8870,9 +8911,18 @@ on(div, "cut", onCopyCut); }; + ContentEditableInput.prototype.screenReaderLabelChanged = function (label) { + // Label for screenreaders, accessibility + if(label) { + this.div.setAttribute('aria-label', label); + } else { + this.div.removeAttribute('aria-label'); + } + }; + ContentEditableInput.prototype.prepareSelection = function () { var result = prepareSelection(this.cm, false); - result.focus = this.cm.state.focused; + result.focus = activeElt(this.div.ownerDocument) == this.div; return result }; @@ -8908,8 +8958,8 @@ var end = to.line < cm.display.viewTo && posToDOM(cm, to); if (!end) { var measure = view[view.length - 1].measure; - var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; - end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]}; + var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; + end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}; } if (!start || !end) { @@ -8968,7 +9018,7 @@ ContentEditableInput.prototype.focus = function () { if (this.cm.options.readOnly != "nocursor") { - if (!this.selectionInEditor()) + if (!this.selectionInEditor() || activeElt(this.div.ownerDocument) != this.div) { this.showSelection(this.prepareSelection(), true); } this.div.focus(); } @@ -8979,9 +9029,11 @@ ContentEditableInput.prototype.supportsTouch = function () { return true }; ContentEditableInput.prototype.receivedFocus = function () { + var this$1 = this; + var input = this; if (this.selectionInEditor()) - { this.pollSelection(); } + { setTimeout(function () { return this$1.pollSelection(); }, 20); } else { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); } @@ -9198,11 +9250,11 @@ addText(cmText); return } - var markerID = node.getAttribute("cm-marker"), range$$1; + var markerID = node.getAttribute("cm-marker"), range; if (markerID) { var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); - if (found.length && (range$$1 = found[0].find(0))) - { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); } + if (found.length && (range = found[0].find(0))) + { addText(getBetween(cm.doc, range.from, range.to).join(lineSep)); } return } if (node.getAttribute("contenteditable") == "false") { return } @@ -9270,13 +9322,13 @@ function find(textNode, topNode, offset) { for (var i = -1; i < (maps ? maps.length : 0); i++) { - var map$$1 = i < 0 ? measure.map : maps[i]; - for (var j = 0; j < map$$1.length; j += 3) { - var curNode = map$$1[j + 2]; + var map = i < 0 ? measure.map : maps[i]; + for (var j = 0; j < map.length; j += 3) { + var curNode = map[j + 2]; if (curNode == textNode || curNode == topNode) { var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); - var ch = map$$1[j] + offset; - if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; } + var ch = map[j] + offset; + if (offset < 0 || curNode != textNode) { ch = map[j + (offset ? 1 : 0)]; } return Pos(line, ch) } } @@ -9318,6 +9370,7 @@ // Used to work around IE issue with selection being forgotten when focus moves away from textarea this.hasSelection = false; this.composing = null; + this.resetting = false; }; TextareaInput.prototype.init = function (display) { @@ -9410,6 +9463,15 @@ this.textarea = this.wrapper.firstChild; }; + TextareaInput.prototype.screenReaderLabelChanged = function (label) { + // Label for screenreaders, accessibility + if(label) { + this.textarea.setAttribute('aria-label', label); + } else { + this.textarea.removeAttribute('aria-label'); + } + }; + TextareaInput.prototype.prepareSelection = function () { // Redraw the selection and/or cursor var cm = this.cm, display = cm.display, doc = cm.doc; @@ -9441,8 +9503,9 @@ // Reset the input to correspond to the selection (or to be empty, // when not typing and nothing is selected) TextareaInput.prototype.reset = function (typing) { - if (this.contextMenuPending || this.composing) { return } + if (this.contextMenuPending || this.composing && typing) { return } var cm = this.cm; + this.resetting = true; if (cm.somethingSelected()) { this.prevInput = ""; var content = cm.getSelection(); @@ -9453,6 +9516,7 @@ this.prevInput = this.textarea.value = ""; if (ie && ie_version >= 9) { this.hasSelection = null; } } + this.resetting = false; }; TextareaInput.prototype.getField = function () { return this.textarea }; @@ -9460,7 +9524,7 @@ TextareaInput.prototype.supportsTouch = function () { return false }; TextareaInput.prototype.focus = function () { - if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { + if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt(this.textarea.ownerDocument) != this.textarea)) { try { this.textarea.focus(); } catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM } @@ -9514,7 +9578,7 @@ // possible when it is clear that nothing happened. hasSelection // will be the case when there is a lot of text in the textarea, // in which case reading its value would be expensive. - if (this.contextMenuPending || !cm.state.focused || + if (this.contextMenuPending || this.resetting || !cm.state.focused || (hasSelection(input) && !prevInput && !this.composing) || cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq) { return false } @@ -9583,9 +9647,9 @@ input.wrapper.style.cssText = "position: static"; te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; var oldScrollY; - if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712) + if (webkit) { oldScrollY = te.ownerDocument.defaultView.scrollY; } // Work around Chrome issue (#2712) display.input.focus(); - if (webkit) { window.scrollTo(null, oldScrollY); } + if (webkit) { te.ownerDocument.defaultView.scrollTo(null, oldScrollY); } display.input.reset(); // Adds "Select all" to context menu in FF if (!cm.somethingSelected()) { te.value = input.prevInput = " "; } @@ -9650,6 +9714,7 @@ TextareaInput.prototype.readOnlyChanged = function (val) { if (!val) { this.reset(); } this.textarea.disabled = val == "nocursor"; + this.textarea.readOnly = !!val; }; TextareaInput.prototype.setUneditable = function () {}; @@ -9666,7 +9731,7 @@ // Set autofocus to true if this textarea is focused, or if it has // autofocus and no other element is focused. if (options.autofocus == null) { - var hasFocus = activeElt(); + var hasFocus = activeElt(textarea.ownerDocument); options.autofocus = hasFocus == textarea || textarea.getAttribute("autofocus") != null && hasFocus == document.body; } @@ -9800,7 +9865,7 @@ addLegacyProps(CodeMirror); - CodeMirror.version = "5.52.0"; + CodeMirror.version = "5.65.9"; return CodeMirror; diff --git a/dcScript/codemirror/mode/css/css.js b/dcScript/codemirror/mode/css/css.js index 05742c5..b0721b4 100644 --- a/dcScript/codemirror/mode/css/css.js +++ b/dcScript/codemirror/mode/css/css.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -29,7 +29,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { valueKeywords = parserConfig.valueKeywords || {}, allowNested = parserConfig.allowNested, lineComment = parserConfig.lineComment, - supportsAtComponent = parserConfig.supportsAtComponent === true; + supportsAtComponent = parserConfig.supportsAtComponent === true, + highlightNonStandardPropertyKeywords = config.highlightNonStandardPropertyKeywords !== false; var type, override; function ret(style, tp) { type = tp; return style; } @@ -77,8 +78,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return ret("qualifier", "qualifier"); } else if (/[:;{}\[\]\(\)]/.test(ch)) { return ret(null, ch); - } else if (stream.match(/[\w-.]+(?=\()/)) { - if (/^(url(-prefix)?|domain|regexp)$/.test(stream.current().toLowerCase())) { + } else if (stream.match(/^[\w-.]+(?=\()/)) { + if (/^(url(-prefix)?|domain|regexp)$/i.test(stream.current())) { state.tokenize = tokenParenthesized; } return ret("variable callee", "variable"); @@ -107,7 +108,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { function tokenParenthesized(stream, state) { stream.next(); // Must be '(' - if (!stream.match(/\s*[\"\')]/, false)) + if (!stream.match(/^\s*[\"\')]/, false)) state.tokenize = tokenString(")"); else state.tokenize = null; @@ -197,7 +198,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { override = "property"; return "maybeprop"; } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) { - override = "string-2"; + override = highlightNonStandardPropertyKeywords ? "string-2" : "property"; return "maybeprop"; } else if (allowNested) { override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag"; @@ -227,7 +228,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { if (type == "}" || type == "{") return popAndPass(type, stream, state); if (type == "(") return pushContext(state, stream, "parens"); - if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) { + if (type == "hash" && !/^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(stream.current())) { override += " error"; } else if (type == "word") { wordAsValue(stream); @@ -291,7 +292,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { else if (propertyKeywords.hasOwnProperty(word)) override = "property"; else if (nonStandardPropertyKeywords.hasOwnProperty(word)) - override = "string-2"; + override = highlightNonStandardPropertyKeywords ? "string-2" : "property"; else if (valueKeywords.hasOwnProperty(word)) override = "atom"; else if (colorKeywords.hasOwnProperty(word)) @@ -442,117 +443,151 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "monochrome", "min-monochrome", "max-monochrome", "resolution", "min-resolution", "max-resolution", "scan", "grid", "orientation", "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio", - "pointer", "any-pointer", "hover", "any-hover" + "pointer", "any-pointer", "hover", "any-hover", "prefers-color-scheme", + "dynamic-range", "video-dynamic-range" ], mediaFeatures = keySet(mediaFeatures_); var mediaValueKeywords_ = [ "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover", - "interlace", "progressive" + "interlace", "progressive", + "dark", "light", + "standard", "high" ], mediaValueKeywords = keySet(mediaValueKeywords_); var propertyKeywords_ = [ "align-content", "align-items", "align-self", "alignment-adjust", - "alignment-baseline", "anchor-point", "animation", "animation-delay", + "alignment-baseline", "all", "anchor-point", "animation", "animation-delay", "animation-direction", "animation-duration", "animation-fill-mode", "animation-iteration-count", "animation-name", "animation-play-state", - "animation-timing-function", "appearance", "azimuth", "backface-visibility", - "background", "background-attachment", "background-blend-mode", "background-clip", - "background-color", "background-image", "background-origin", "background-position", - "background-repeat", "background-size", "baseline-shift", "binding", - "bleed", "bookmark-label", "bookmark-level", "bookmark-state", - "bookmark-target", "border", "border-bottom", "border-bottom-color", - "border-bottom-left-radius", "border-bottom-right-radius", - "border-bottom-style", "border-bottom-width", "border-collapse", - "border-color", "border-image", "border-image-outset", + "animation-timing-function", "appearance", "azimuth", "backdrop-filter", + "backface-visibility", "background", "background-attachment", + "background-blend-mode", "background-clip", "background-color", + "background-image", "background-origin", "background-position", + "background-position-x", "background-position-y", "background-repeat", + "background-size", "baseline-shift", "binding", "bleed", "block-size", + "bookmark-label", "bookmark-level", "bookmark-state", "bookmark-target", + "border", "border-bottom", "border-bottom-color", "border-bottom-left-radius", + "border-bottom-right-radius", "border-bottom-style", "border-bottom-width", + "border-collapse", "border-color", "border-image", "border-image-outset", "border-image-repeat", "border-image-slice", "border-image-source", - "border-image-width", "border-left", "border-left-color", - "border-left-style", "border-left-width", "border-radius", "border-right", - "border-right-color", "border-right-style", "border-right-width", - "border-spacing", "border-style", "border-top", "border-top-color", - "border-top-left-radius", "border-top-right-radius", "border-top-style", - "border-top-width", "border-width", "bottom", "box-decoration-break", - "box-shadow", "box-sizing", "break-after", "break-before", "break-inside", - "caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count", - "column-fill", "column-gap", "column-rule", "column-rule-color", - "column-rule-style", "column-rule-width", "column-span", "column-width", - "columns", "content", "counter-increment", "counter-reset", "crop", "cue", - "cue-after", "cue-before", "cursor", "direction", "display", - "dominant-baseline", "drop-initial-after-adjust", - "drop-initial-after-align", "drop-initial-before-adjust", - "drop-initial-before-align", "drop-initial-size", "drop-initial-value", - "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis", - "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", - "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings", - "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust", - "font-stretch", "font-style", "font-synthesis", "font-variant", - "font-variant-alternates", "font-variant-caps", "font-variant-east-asian", - "font-variant-ligatures", "font-variant-numeric", "font-variant-position", - "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", - "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap", - "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap", - "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns", - "grid-template-rows", "hanging-punctuation", "height", "hyphens", - "icon", "image-orientation", "image-rendering", "image-resolution", - "inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing", - "line-break", "line-height", "line-stacking", "line-stacking-ruby", + "border-image-width", "border-left", "border-left-color", "border-left-style", + "border-left-width", "border-radius", "border-right", "border-right-color", + "border-right-style", "border-right-width", "border-spacing", "border-style", + "border-top", "border-top-color", "border-top-left-radius", + "border-top-right-radius", "border-top-style", "border-top-width", + "border-width", "bottom", "box-decoration-break", "box-shadow", "box-sizing", + "break-after", "break-before", "break-inside", "caption-side", "caret-color", + "clear", "clip", "color", "color-profile", "column-count", "column-fill", + "column-gap", "column-rule", "column-rule-color", "column-rule-style", + "column-rule-width", "column-span", "column-width", "columns", "contain", + "content", "counter-increment", "counter-reset", "crop", "cue", "cue-after", + "cue-before", "cursor", "direction", "display", "dominant-baseline", + "drop-initial-after-adjust", "drop-initial-after-align", + "drop-initial-before-adjust", "drop-initial-before-align", "drop-initial-size", + "drop-initial-value", "elevation", "empty-cells", "fit", "fit-content", "fit-position", + "flex", "flex-basis", "flex-direction", "flex-flow", "flex-grow", + "flex-shrink", "flex-wrap", "float", "float-offset", "flow-from", "flow-into", + "font", "font-family", "font-feature-settings", "font-kerning", + "font-language-override", "font-optical-sizing", "font-size", + "font-size-adjust", "font-stretch", "font-style", "font-synthesis", + "font-variant", "font-variant-alternates", "font-variant-caps", + "font-variant-east-asian", "font-variant-ligatures", "font-variant-numeric", + "font-variant-position", "font-variation-settings", "font-weight", "gap", + "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", "grid-auto-rows", + "grid-column", "grid-column-end", "grid-column-gap", "grid-column-start", + "grid-gap", "grid-row", "grid-row-end", "grid-row-gap", "grid-row-start", + "grid-template", "grid-template-areas", "grid-template-columns", + "grid-template-rows", "hanging-punctuation", "height", "hyphens", "icon", + "image-orientation", "image-rendering", "image-resolution", "inline-box-align", + "inset", "inset-block", "inset-block-end", "inset-block-start", "inset-inline", + "inset-inline-end", "inset-inline-start", "isolation", "justify-content", + "justify-items", "justify-self", "left", "letter-spacing", "line-break", + "line-height", "line-height-step", "line-stacking", "line-stacking-ruby", "line-stacking-shift", "line-stacking-strategy", "list-style", "list-style-image", "list-style-position", "list-style-type", "margin", - "margin-bottom", "margin-left", "margin-right", "margin-top", - "marks", "marquee-direction", "marquee-loop", - "marquee-play-count", "marquee-speed", "marquee-style", "max-height", - "max-width", "min-height", "min-width", "mix-blend-mode", "move-to", "nav-down", "nav-index", - "nav-left", "nav-right", "nav-up", "object-fit", "object-position", - "opacity", "order", "orphans", "outline", - "outline-color", "outline-offset", "outline-style", "outline-width", - "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y", - "padding", "padding-bottom", "padding-left", "padding-right", "padding-top", - "page", "page-break-after", "page-break-before", "page-break-inside", - "page-policy", "pause", "pause-after", "pause-before", "perspective", - "perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position", - "presentation-level", "punctuation-trim", "quotes", "region-break-after", - "region-break-before", "region-break-inside", "region-fragment", - "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness", - "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang", - "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin", - "shape-outside", "size", "speak", "speak-as", "speak-header", - "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set", - "tab-size", "table-layout", "target", "target-name", "target-new", - "target-position", "text-align", "text-align-last", "text-decoration", + "margin-bottom", "margin-left", "margin-right", "margin-top", "marks", + "marquee-direction", "marquee-loop", "marquee-play-count", "marquee-speed", + "marquee-style", "mask-clip", "mask-composite", "mask-image", "mask-mode", + "mask-origin", "mask-position", "mask-repeat", "mask-size","mask-type", + "max-block-size", "max-height", "max-inline-size", + "max-width", "min-block-size", "min-height", "min-inline-size", "min-width", + "mix-blend-mode", "move-to", "nav-down", "nav-index", "nav-left", "nav-right", + "nav-up", "object-fit", "object-position", "offset", "offset-anchor", + "offset-distance", "offset-path", "offset-position", "offset-rotate", + "opacity", "order", "orphans", "outline", "outline-color", "outline-offset", + "outline-style", "outline-width", "overflow", "overflow-style", + "overflow-wrap", "overflow-x", "overflow-y", "padding", "padding-bottom", + "padding-left", "padding-right", "padding-top", "page", "page-break-after", + "page-break-before", "page-break-inside", "page-policy", "pause", + "pause-after", "pause-before", "perspective", "perspective-origin", "pitch", + "pitch-range", "place-content", "place-items", "place-self", "play-during", + "position", "presentation-level", "punctuation-trim", "quotes", + "region-break-after", "region-break-before", "region-break-inside", + "region-fragment", "rendering-intent", "resize", "rest", "rest-after", + "rest-before", "richness", "right", "rotate", "rotation", "rotation-point", + "row-gap", "ruby-align", "ruby-overhang", "ruby-position", "ruby-span", + "scale", "scroll-behavior", "scroll-margin", "scroll-margin-block", + "scroll-margin-block-end", "scroll-margin-block-start", "scroll-margin-bottom", + "scroll-margin-inline", "scroll-margin-inline-end", + "scroll-margin-inline-start", "scroll-margin-left", "scroll-margin-right", + "scroll-margin-top", "scroll-padding", "scroll-padding-block", + "scroll-padding-block-end", "scroll-padding-block-start", + "scroll-padding-bottom", "scroll-padding-inline", "scroll-padding-inline-end", + "scroll-padding-inline-start", "scroll-padding-left", "scroll-padding-right", + "scroll-padding-top", "scroll-snap-align", "scroll-snap-type", + "shape-image-threshold", "shape-inside", "shape-margin", "shape-outside", + "size", "speak", "speak-as", "speak-header", "speak-numeral", + "speak-punctuation", "speech-rate", "stress", "string-set", "tab-size", + "table-layout", "target", "target-name", "target-new", "target-position", + "text-align", "text-align-last", "text-combine-upright", "text-decoration", "text-decoration-color", "text-decoration-line", "text-decoration-skip", - "text-decoration-style", "text-emphasis", "text-emphasis-color", - "text-emphasis-position", "text-emphasis-style", "text-height", - "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow", - "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position", - "text-wrap", "top", "transform", "transform-origin", "transform-style", - "transition", "transition-delay", "transition-duration", - "transition-property", "transition-timing-function", "unicode-bidi", - "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration", - "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", - "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break", - "word-spacing", "word-wrap", "z-index", + "text-decoration-skip-ink", "text-decoration-style", "text-emphasis", + "text-emphasis-color", "text-emphasis-position", "text-emphasis-style", + "text-height", "text-indent", "text-justify", "text-orientation", + "text-outline", "text-overflow", "text-rendering", "text-shadow", + "text-size-adjust", "text-space-collapse", "text-transform", + "text-underline-position", "text-wrap", "top", "touch-action", "transform", "transform-origin", + "transform-style", "transition", "transition-delay", "transition-duration", + "transition-property", "transition-timing-function", "translate", + "unicode-bidi", "user-select", "vertical-align", "visibility", "voice-balance", + "voice-duration", "voice-family", "voice-pitch", "voice-range", "voice-rate", + "voice-stress", "voice-volume", "volume", "white-space", "widows", "width", + "will-change", "word-break", "word-spacing", "word-wrap", "writing-mode", "z-index", // SVG-specific "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", "color-interpolation", "color-interpolation-filters", "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", - "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke", + "marker", "marker-end", "marker-mid", "marker-start", "paint-order", "shape-rendering", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", - "glyph-orientation-vertical", "text-anchor", "writing-mode" + "glyph-orientation-vertical", "text-anchor", "writing-mode", ], propertyKeywords = keySet(propertyKeywords_); var nonStandardPropertyKeywords_ = [ + "accent-color", "aspect-ratio", "border-block", "border-block-color", "border-block-end", + "border-block-end-color", "border-block-end-style", "border-block-end-width", + "border-block-start", "border-block-start-color", "border-block-start-style", + "border-block-start-width", "border-block-style", "border-block-width", + "border-inline", "border-inline-color", "border-inline-end", + "border-inline-end-color", "border-inline-end-style", + "border-inline-end-width", "border-inline-start", "border-inline-start-color", + "border-inline-start-style", "border-inline-start-width", + "border-inline-style", "border-inline-width", "content-visibility", "margin-block", + "margin-block-end", "margin-block-start", "margin-inline", "margin-inline-end", + "margin-inline-start", "overflow-anchor", "overscroll-behavior", "padding-block", "padding-block-end", + "padding-block-start", "padding-inline", "padding-inline-end", + "padding-inline-start", "scroll-snap-stop", "scrollbar-3d-light-color", "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", - "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside", - "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", - "searchfield-results-decoration", "zoom" + "scrollbar-track-color", "searchfield-cancel-button", "searchfield-decoration", + "searchfield-results-button", "searchfield-results-decoration", "shape-inside", "zoom" ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_); var fontProperties_ = [ - "font-family", "src", "unicode-range", "font-variant", "font-feature-settings", - "font-stretch", "font-weight", "font-style" + "font-display", "font-family", "src", "unicode-range", "font-variant", + "font-feature-settings", "font-stretch", "font-weight", "font-style" ], fontProperties = keySet(fontProperties_); var counterDescriptors_ = [ @@ -565,16 +600,16 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", - "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", + "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", - "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", - "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", + "darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", + "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", - "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink", - "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", + "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink", + "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", @@ -584,7 +619,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", - "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", + "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen" ], colorKeywords = keySet(colorKeywords_); @@ -594,22 +629,22 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page", - "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary", - "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", - "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel", + "avoid-region", "axis-pan", "background", "backwards", "baseline", "below", "bidi-override", "binary", + "bengali", "blink", "block", "block-axis", "blur", "bold", "bolder", "border", "border-box", + "both", "bottom", "break", "break-all", "break-word", "brightness", "bullets", "button", "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian", "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch", "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse", - "compact", "condensed", "contain", "content", "contents", - "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop", - "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal", + "compact", "condensed", "conic-gradient", "contain", "content", "contents", + "content-box", "context-menu", "continuous", "contrast", "copy", "counter", "counters", "cover", "crop", + "cross", "crosshair", "cubic-bezier", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal", "decimal-leading-zero", "default", "default-button", "dense", "destination-atop", "destination-in", "destination-out", "destination-over", "devanagari", "difference", "disc", "discard", "disclosure-closed", "disclosure-open", "document", "dot-dash", "dot-dot-dash", - "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", + "dotted", "double", "down", "drop-shadow", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede", "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er", "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", @@ -618,11 +653,11 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed", - "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", - "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove", + "extra-expanded", "fantasy", "fast", "fill", "fill-box", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", + "forwards", "from", "geometricPrecision", "georgian", "grayscale", "graytext", "grid", "groove", "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew", "help", "hidden", "hide", "higher", "highlight", "highlighttext", - "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore", + "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "hue-rotate", "icon", "ignore", "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert", @@ -633,41 +668,37 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem", "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", - "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d", - "media-controls-background", "media-current-time-display", - "media-fullscreen-button", "media-mute-button", "media-play-button", - "media-return-to-realtime-button", "media-rewind-button", - "media-seek-back-button", "media-seek-forward-button", "media-slider", - "media-sliderthumb", "media-time-remaining-display", "media-volume-slider", - "media-volume-slider-container", "media-volume-sliderthumb", "medium", - "menu", "menulist", "menulist-button", "menulist-text", - "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", - "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize", + "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "manipulation", "match", "matrix", "matrix3d", + "media-play-button", "media-slider", "media-sliderthumb", + "media-volume-slider", "media-volume-sliderthumb", "medium", + "menu", "menulist", "menulist-button", + "menutext", "message-box", "middle", "min-intrinsic", + "mix", "mongolian", "monospace", "move", "multiple", "multiple_mask_images", "multiply", "myanmar", "n-resize", "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote", "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", - "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter", + "painted", "page", "paused", "persian", "perspective", "pinch-zoom", "plus-darker", "plus-lighter", "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button", "radial-gradient", "radio", "read-only", "read-write", "read-write-plaintext-only", "rectangle", "region", - "relative", "repeat", "repeating-linear-gradient", - "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse", + "relative", "repeat", "repeating-linear-gradient", "repeating-radial-gradient", + "repeating-conic-gradient", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY", "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running", - "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen", + "s-resize", "sans-serif", "saturate", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen", "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield", "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end", - "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", + "semi-condensed", "semi-expanded", "separate", "sepia", "serif", "show", "sidama", "simp-chinese-formal", "simp-chinese-informal", "single", "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal", "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali", "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square", - "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub", - "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table", + "square-button", "start", "static", "status-bar", "stretch", "stroke", "stroke-box", "sub", + "subpixel-antialiased", "svg_masks", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row", "table-row-group", "tamil", @@ -677,10 +708,10 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", "trad-chinese-formal", "trad-chinese-informal", "transform", "translate", "translate3d", "translateX", "translateY", "translateZ", - "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up", + "transparent", "ultra-condensed", "ultra-expanded", "underline", "unidirectional-pan", "unset", "up", "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", - "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", + "var", "vertical", "vertical-text", "view-box", "visible", "visibleFill", "visiblePainted", "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor", "xx-large", "xx-small" @@ -748,7 +779,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { } }, ":": function(stream) { - if (stream.match(/\s*\{/, false)) + if (stream.match(/^\s*\{/, false)) return [null, null] return false; }, diff --git a/dcScript/codemirror/mode/css/gss.html b/dcScript/codemirror/mode/css/gss.html new file mode 100644 index 0000000..aa12bfb --- /dev/null +++ b/dcScript/codemirror/mode/css/gss.html @@ -0,0 +1,104 @@ + + +CodeMirror: Closure Stylesheets (GSS) mode + + + + + + + + + + + + + +
+

Closure Stylesheets (GSS) mode

+
+ + +

A mode for Closure Stylesheets (GSS).

+

MIME type defined: text/x-gss.

+ +

Parsing/Highlighting Tests: normal, verbose.

+ +
diff --git a/dcScript/codemirror/mode/css/gss_test.js b/dcScript/codemirror/mode/css/gss_test.js new file mode 100644 index 0000000..0901563 --- /dev/null +++ b/dcScript/codemirror/mode/css/gss_test.js @@ -0,0 +1,17 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function() { + "use strict"; + + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-gss"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "gss"); } + + MT("atComponent", + "[def @component] {", + "[tag foo] {", + " [property color]: [keyword black];", + "}", + "}"); + +})(); diff --git a/dcScript/codemirror/mode/css/index.html b/dcScript/codemirror/mode/css/index.html new file mode 100644 index 0000000..233d19b --- /dev/null +++ b/dcScript/codemirror/mode/css/index.html @@ -0,0 +1,81 @@ + + +CodeMirror: CSS mode + + + + + + + + + + + + +
+

CSS mode

+
+ + +

CSS mode supports this option:

+ +
highlightNonStandardPropertyKeywords: boolean
+
Whether to highlight non-standard CSS property keywords such as margin-inline or zoom (default: true).
+
+ +

MIME types defined: text/css, text/x-scss (demo), text/x-less (demo).

+ +

Parsing/Highlighting Tests: normal, verbose.

+ +
diff --git a/dcScript/codemirror/mode/css/less.html b/dcScript/codemirror/mode/css/less.html new file mode 100644 index 0000000..ea7db00 --- /dev/null +++ b/dcScript/codemirror/mode/css/less.html @@ -0,0 +1,152 @@ + + +CodeMirror: LESS mode + + + + + + + + + + +
+

LESS mode

+
+ + +

The LESS mode is a sub-mode of the CSS mode (defined in css.js).

+ +

Parsing/Highlighting Tests: normal, verbose.

+
diff --git a/dcScript/codemirror/mode/css/less_test.js b/dcScript/codemirror/mode/css/less_test.js new file mode 100644 index 0000000..cf367ea --- /dev/null +++ b/dcScript/codemirror/mode/css/less_test.js @@ -0,0 +1,54 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function() { + "use strict"; + + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-less"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "less"); } + + MT("variable", + "[variable-2 @base]: [atom #f04615];", + "[qualifier .class] {", + " [property width]: [variable&callee percentage]([number 0.5]); [comment // returns `50%`]", + " [property color]: [variable&callee saturate]([variable-2 @base], [number 5%]);", + "}"); + + MT("amp", + "[qualifier .child], [qualifier .sibling] {", + " [qualifier .parent] [atom &] {", + " [property color]: [keyword black];", + " }", + " [atom &] + [atom &] {", + " [property color]: [keyword red];", + " }", + "}"); + + MT("mixin", + "[qualifier .mixin] ([variable dark]; [variable-2 @color]) {", + " [property color]: [variable&callee darken]([variable-2 @color], [number 10%]);", + "}", + "[qualifier .mixin] ([variable light]; [variable-2 @color]) {", + " [property color]: [variable&callee lighten]([variable-2 @color], [number 10%]);", + "}", + "[qualifier .mixin] ([variable-2 @_]; [variable-2 @color]) {", + " [property display]: [atom block];", + "}", + "[variable-2 @switch]: [variable light];", + "[qualifier .class] {", + " [qualifier .mixin]([variable-2 @switch]; [atom #888]);", + "}"); + + MT("nest", + "[qualifier .one] {", + " [def @media] ([property width]: [number 400px]) {", + " [property font-size]: [number 1.2em];", + " [def @media] [attribute print] [keyword and] [property color] {", + " [property color]: [keyword blue];", + " }", + " }", + "}"); + + + MT("interpolation", ".@{[variable foo]} { [property font-weight]: [atom bold]; }"); +})(); diff --git a/dcScript/codemirror/mode/css/scss.html b/dcScript/codemirror/mode/css/scss.html new file mode 100644 index 0000000..75ef4f9 --- /dev/null +++ b/dcScript/codemirror/mode/css/scss.html @@ -0,0 +1,158 @@ + + +CodeMirror: SCSS mode + + + + + + + + + + +
+

SCSS mode

+
+ + +

The SCSS mode is a sub-mode of the CSS mode (defined in css.js).

+ +

Parsing/Highlighting Tests: normal, verbose.

+ +
diff --git a/dcScript/codemirror/mode/css/scss_test.js b/dcScript/codemirror/mode/css/scss_test.js new file mode 100644 index 0000000..14c1d13 --- /dev/null +++ b/dcScript/codemirror/mode/css/scss_test.js @@ -0,0 +1,110 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-scss"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); } + + MT('url_with_quotation', + "[tag foo] { [property background]:[variable&callee url]([string test.jpg]) }"); + + MT('url_with_double_quotes', + "[tag foo] { [property background]:[variable&callee url]([string \"test.jpg\"]) }"); + + MT('url_with_single_quotes', + "[tag foo] { [property background]:[variable&callee url]([string \'test.jpg\']) }"); + + MT('string', + "[def @import] [string \"compass/css3\"]"); + + MT('important_keyword', + "[tag foo] { [property background]:[variable&callee url]([string \'test.jpg\']) [keyword !important] }"); + + MT('variable', + "[variable-2 $blue]:[atom #333]"); + + MT('variable_as_attribute', + "[tag foo] { [property color]:[variable-2 $blue] }"); + + MT('numbers', + "[tag foo] { [property padding]:[number 10px] [number 10] [number 10em] [number 8in] }"); + + MT('number_percentage', + "[tag foo] { [property width]:[number 80%] }"); + + MT('selector', + "[builtin #hello][qualifier .world]{}"); + + MT('singleline_comment', + "[comment // this is a comment]"); + + MT('multiline_comment', + "[comment /*foobar*/]"); + + MT('attribute_with_hyphen', + "[tag foo] { [property font-size]:[number 10px] }"); + + MT('string_after_attribute', + "[tag foo] { [property content]:[string \"::\"] }"); + + MT('directives', + "[def @include] [qualifier .mixin]"); + + MT('basic_structure', + "[tag p] { [property background]:[keyword red]; }"); + + MT('nested_structure', + "[tag p] { [tag a] { [property color]:[keyword red]; } }"); + + MT('mixin', + "[def @mixin] [tag table-base] {}"); + + MT('number_without_semicolon', + "[tag p] {[property width]:[number 12]}", + "[tag a] {[property color]:[keyword red];}"); + + MT('atom_in_nested_block', + "[tag p] { [tag a] { [property color]:[atom #000]; } }"); + + MT('interpolation_in_property', + "[tag foo] { #{[variable-2 $hello]}:[number 2]; }"); + + MT('interpolation_in_selector', + "[tag foo]#{[variable-2 $hello]} { [property color]:[atom #000]; }"); + + MT('interpolation_error', + "[tag foo]#{[variable foo]} { [property color]:[atom #000]; }"); + + MT("divide_operator", + "[tag foo] { [property width]:[number 4] [operator /] [number 2] }"); + + MT('nested_structure_with_id_selector', + "[tag p] { [builtin #hello] { [property color]:[keyword red]; } }"); + + MT('indent_mixin', + "[def @mixin] [tag container] (", + " [variable-2 $a]: [number 10],", + " [variable-2 $b]: [number 10])", + "{}"); + + MT('indent_nested', + "[tag foo] {", + " [tag bar] {", + " }", + "}"); + + MT('indent_parentheses', + "[tag foo] {", + " [property color]: [variable&callee darken]([variable-2 $blue],", + " [number 9%]);", + "}"); + + MT('indent_vardef', + "[variable-2 $name]:", + " [string 'val'];", + "[tag tag] {", + " [tag inner] {", + " [property margin]: [number 3px];", + " }", + "}"); +})(); diff --git a/dcScript/codemirror/mode/css/test.js b/dcScript/codemirror/mode/css/test.js new file mode 100644 index 0000000..573207e --- /dev/null +++ b/dcScript/codemirror/mode/css/test.js @@ -0,0 +1,217 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "css"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + // Error, because "foobarhello" is neither a known type or property, but + // property was expected (after "and"), and it should be in parentheses. + MT("atMediaUnknownType", + "[def @media] [attribute screen] [keyword and] [error foobarhello] { }"); + + // Soft error, because "foobarhello" is not a known property or type. + MT("atMediaUnknownProperty", + "[def @media] [attribute screen] [keyword and] ([error foobarhello]) { }"); + + // Make sure nesting works with media queries + MT("atMediaMaxWidthNested", + "[def @media] [attribute screen] [keyword and] ([property max-width]: [number 25px]) { [tag foo] { } }"); + + MT("atMediaFeatureValueKeyword", + "[def @media] ([property orientation]: [keyword landscape]) { }"); + + MT("atMediaUnknownFeatureValueKeyword", + "[def @media] ([property orientation]: [error upsidedown]) { }"); + + MT("atMediaUppercase", + "[def @MEDIA] ([property orienTAtion]: [keyword landScape]) { }"); + + MT("tagSelector", + "[tag foo] { }"); + + MT("classSelector", + "[qualifier .foo-bar_hello] { }"); + + MT("idSelector", + "[builtin #foo] { [error #foo] }"); + + MT("tagSelectorUnclosed", + "[tag foo] { [property margin]: [number 0] } [tag bar] { }"); + + MT("tagStringNoQuotes", + "[tag foo] { [property font-family]: [variable hello] [variable world]; }"); + + MT("tagStringDouble", + "[tag foo] { [property font-family]: [string \"hello world\"]; }"); + + MT("tagStringSingle", + "[tag foo] { [property font-family]: [string 'hello world']; }"); + + MT("tagColorKeyword", + "[tag foo] {", + " [property color]: [keyword black];", + " [property color]: [keyword navy];", + " [property color]: [keyword yellow];", + "}"); + + MT("tagColorHex3", + "[tag foo] { [property background]: [atom #fff]; }"); + + MT("tagColorHex4", + "[tag foo] { [property background]: [atom #ffff]; }"); + + MT("tagColorHex6", + "[tag foo] { [property background]: [atom #ffffff]; }"); + + MT("tagColorHex8", + "[tag foo] { [property background]: [atom #ffffffff]; }"); + + MT("tagColorHex5Invalid", + "[tag foo] { [property background]: [atom&error #fffff]; }"); + + MT("tagColorHexInvalid", + "[tag foo] { [property background]: [atom&error #ffg]; }"); + + MT("tagNegativeNumber", + "[tag foo] { [property margin]: [number -5px]; }"); + + MT("tagPositiveNumber", + "[tag foo] { [property padding]: [number 5px]; }"); + + MT("tagVendor", + "[tag foo] { [meta -foo-][property box-sizing]: [meta -foo-][atom border-box]; }"); + + MT("tagBogusProperty", + "[tag foo] { [property&error barhelloworld]: [number 0]; }"); + + MT("tagTwoProperties", + "[tag foo] { [property margin]: [number 0]; [property padding]: [number 0]; }"); + + MT("tagTwoPropertiesURL", + "[tag foo] { [property background]: [variable&callee url]([string //example.com/foo.png]); [property padding]: [number 0]; }"); + + MT("indent_tagSelector", + "[tag strong], [tag em] {", + " [property background]: [variable&callee rgba](", + " [number 255], [number 255], [number 0], [number .2]", + " );", + "}"); + + MT("indent_atMedia", + "[def @media] {", + " [tag foo] {", + " [property color]:", + " [keyword yellow];", + " }", + "}"); + + MT("indent_comma", + "[tag foo] {", + " [property font-family]: [variable verdana],", + " [atom sans-serif];", + "}"); + + MT("indent_parentheses", + "[tag foo]:[variable-3 before] {", + " [property background]: [variable&callee url](", + "[string blahblah]", + "[string etc]", + "[string ]) [keyword !important];", + "}"); + + MT("font_face", + "[def @font-face] {", + " [property font-family]: [string 'myfont'];", + " [error nonsense]: [string 'abc'];", + " [property src]: [variable&callee url]([string http://blah]),", + " [variable&callee url]([string http://foo]);", + "}"); + + MT("empty_url", + "[def @import] [variable&callee url]() [attribute screen];"); + + MT("parens", + "[qualifier .foo] {", + " [property background-image]: [variable&callee fade]([atom #000], [number 20%]);", + " [property border-image]: [variable&callee linear-gradient](", + " [atom to] [atom bottom],", + " [variable&callee fade]([atom #000], [number 20%]) [number 0%],", + " [variable&callee fade]([atom #000], [number 20%]) [number 100%]", + " );", + "}"); + + MT("css_variable", + ":[variable-3 root] {", + " [variable-2 --main-color]: [atom #06c];", + "}", + "[tag h1][builtin #foo] {", + " [property color]: [variable&callee var]([variable-2 --main-color]);", + "}"); + + MT("blank_css_variable", + ":[variable-3 root] {", + " [variable-2 --]: [atom #06c];", + "}", + "[tag h1][builtin #foo] {", + " [property color]: [variable&callee var]([variable-2 --]);", + "}"); + + MT("supports", + "[def @supports] ([keyword not] (([property text-align-last]: [atom justify]) [keyword or] ([meta -moz-][property text-align-last]: [atom justify])) {", + " [property text-align-last]: [atom justify];", + "}"); + + MT("document", + "[def @document] [variable&callee url]([string http://blah]),", + " [variable&callee url-prefix]([string https://]),", + " [variable&callee domain]([string blah.com]),", + " [variable&callee regexp]([string \".*blah.+\"]) {", + " [builtin #id] {", + " [property background-color]: [keyword white];", + " }", + " [tag foo] {", + " [property font-family]: [variable Verdana], [atom sans-serif];", + " }", + "}"); + + MT("document_url", + "[def @document] [variable&callee url]([string http://blah]) { [qualifier .class] { } }"); + + MT("document_urlPrefix", + "[def @document] [variable&callee url-prefix]([string https://]) { [builtin #id] { } }"); + + MT("document_domain", + "[def @document] [variable&callee domain]([string blah.com]) { [tag foo] { } }"); + + MT("document_regexp", + "[def @document] [variable&callee regexp]([string \".*blah.+\"]) { [builtin #id] { } }"); + + MT("counter-style", + "[def @counter-style] [variable binary] {", + " [property system]: [atom numeric];", + " [property symbols]: [number 0] [number 1];", + " [property suffix]: [string \".\"];", + " [property range]: [atom infinite];", + " [property speak-as]: [atom numeric];", + "}"); + + MT("counter-style-additive-symbols", + "[def @counter-style] [variable simple-roman] {", + " [property system]: [atom additive];", + " [property additive-symbols]: [number 10] [variable X], [number 5] [variable V], [number 1] [variable I];", + " [property range]: [number 1] [number 49];", + "}"); + + MT("counter-style-use", + "[tag ol][qualifier .roman] { [property list-style]: [variable simple-roman]; }"); + + MT("counter-style-symbols", + "[tag ol] { [property list-style]: [variable&callee symbols]([atom cyclic] [string \"*\"] [string \"\\2020\"] [string \"\\2021\"] [string \"\\A7\"]); }"); + + MT("comment-does-not-disrupt", + "[def @font-face] [comment /* foo */] {", + " [property src]: [variable&callee url]([string x]);", + " [property font-family]: [variable One];", + "}") +})(); diff --git a/dcScript/codemirror/mode/htmlmixed/htmlmixed.js b/dcScript/codemirror/mode/htmlmixed/htmlmixed.js index 8341ac8..3f6d8b7 100644 --- a/dcScript/codemirror/mode/htmlmixed/htmlmixed.js +++ b/dcScript/codemirror/mode/htmlmixed/htmlmixed.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -50,7 +50,7 @@ } function getTagRegexp(tagName, anchored) { - return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i"); + return new RegExp((anchored ? "^" : "") + "<\/\\s*" + tagName + "\\s*>", "i"); } function addTags(from, to) { @@ -74,7 +74,8 @@ name: "xml", htmlMode: true, multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, - multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag + multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag, + allowMissingTagName: parserConfig.allowMissingTagName, }); var tags = {}; diff --git a/dcScript/codemirror/mode/htmlmixed/index.html b/dcScript/codemirror/mode/htmlmixed/index.html new file mode 100644 index 0000000..9548361 --- /dev/null +++ b/dcScript/codemirror/mode/htmlmixed/index.html @@ -0,0 +1,100 @@ + + +CodeMirror: HTML mixed mode + + + + + + + + + + + + + + +
+

HTML mixed mode

+
+ + +

The HTML mixed mode depends on the XML, JavaScript, and CSS modes.

+ +

It takes an optional mode configuration + option, tags, which can be used to add custom + behavior for specific tags. When given, it should be an object + mapping tag names (for example script) to arrays or + three-element arrays. Those inner arrays indicate [attributeName, + valueRegexp, modeSpec] + specifications. For example, you could use ["type", /^foo$/, + "foo"] to map the attribute type="foo" to + the foo mode. When the first two fields are null + ([null, null, "mode"]), the given mode is used for + any such tag that doesn't match any of the previously given + attributes. For example:

+ +
var myModeSpec = {
+  name: "htmlmixed",
+  tags: {
+    style: [["type", /^text\/(x-)?scss$/, "text/x-scss"],
+            [null, null, "css"]],
+    custom: [[null, null, "customMode"]]
+  }
+}
+ +

MIME types defined: text/html + (redefined, only takes effect if you load this parser after the + XML parser).

+ +
diff --git a/dcScript/codemirror/mode/javascript/index.html b/dcScript/codemirror/mode/javascript/index.html new file mode 100644 index 0000000..f4be5ea --- /dev/null +++ b/dcScript/codemirror/mode/javascript/index.html @@ -0,0 +1,118 @@ + + +CodeMirror: JavaScript mode + + + + + + + + + + + + +
+

JavaScript mode

+ + +
+ + + +

+ JavaScript mode supports several configuration options: +

    +
  • json which will set the mode to expect JSON + data rather than a JavaScript program.
  • +
  • jsonld which will set the mode to expect + JSON-LD linked data rather + than a JavaScript program (demo).
  • +
  • typescript which will activate additional + syntax highlighting and some other things for TypeScript code + (demo).
  • +
  • trackScope can be set to false to turn off + tracking of local variables. This will prevent locals from + getting the "variable-2" token type, and will + break completion of locals with javascript-hint.
  • +
  • statementIndent which (given a number) will + determine the amount of indentation to use for statements + continued on a new line.
  • +
  • wordCharacters, a regexp that indicates which + characters should be considered part of an identifier. + Defaults to /[\w$]/, which does not handle + non-ASCII identifiers. Can be set to something more elaborate + to improve Unicode support.
  • +
+

+ +

MIME types defined: text/javascript, application/javascript, application/x-javascript, text/ecmascript, application/ecmascript, application/json, application/x-json, application/manifest+json, application/ld+json, text/typescript, application/typescript.

+
diff --git a/dcScript/codemirror/mode/javascript/javascript.js b/dcScript/codemirror/mode/javascript/javascript.js index 04d01fc..48a46d6 100644 --- a/dcScript/codemirror/mode/javascript/javascript.js +++ b/dcScript/codemirror/mode/javascript/javascript.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -16,6 +16,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var statementIndent = parserConfig.statementIndent; var jsonldMode = parserConfig.jsonld; var jsonMode = parserConfig.json || jsonldMode; + var trackScope = parserConfig.trackScope !== false var isTS = parserConfig.typescript; var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; @@ -98,21 +99,25 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } else if (ch == "`") { state.tokenize = tokenQuasi; return tokenQuasi(stream, state); - } else if (ch == "#") { + } else if (ch == "#" && stream.peek() == "!") { stream.skipToEnd(); - return ret("error", "error"); - } else if (ch == "<" && stream.match("!--") || ch == "-" && stream.match("->")) { + return ret("meta", "meta"); + } else if (ch == "#" && stream.eatWhile(wordRE)) { + return ret("variable", "property") + } else if (ch == "<" && stream.match("!--") || + (ch == "-" && stream.match("->") && !/\S/.test(stream.string.slice(0, stream.start)))) { stream.skipToEnd() return ret("comment", "comment") } else if (isOperatorChar.test(ch)) { if (ch != ">" || !state.lexical || state.lexical.type != ">") { if (stream.eat("=")) { if (ch == "!" || ch == "=") stream.eat("=") - } else if (/[<>*+\-]/.test(ch)) { + } else if (/[<>*+\-|&?]/.test(ch)) { stream.eat(ch) if (ch == ">") stream.eat(ch) } } + if (ch == "?" && stream.eat(".")) return ret(".") return ret("operator", "operator", stream.current()); } else if (wordRE.test(ch)) { stream.eatWhile(wordRE); @@ -122,7 +127,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var kw = keywords[word] return ret(kw.type, kw.style, word) } - if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\[\(\w]/, false)) + if (word == "async" && stream.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/, false)) return ret("async", "keyword", word) } return ret("variable", "variable", word) @@ -214,7 +219,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { // Parser - var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true}; + var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, + "regexp": true, "this": true, "import": true, "jsonld-keyword": true}; function JSLexical(indented, column, type, align, prev, info) { this.indented = indented; @@ -226,6 +232,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function inScope(state, varname) { + if (!trackScope) return false for (var v = state.localVars; v; v = v.next) if (v.name == varname) return true; for (var cx = state.context; cx; cx = cx.prev) { @@ -272,6 +279,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function register(varname) { var state = cx.state; cx.marked = "def"; + if (!trackScope) return if (state.context) { if (state.lexical.info == "var" && state.context && state.context.block) { // FIXME function decls are also not block scoped @@ -322,6 +330,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { cx.state.context = new Context(cx.state.context, cx.state.localVars, true) cx.state.localVars = null } + pushcontext.lex = pushblockcontext.lex = true function popcontext() { cx.state.localVars = cx.state.context.vars cx.state.context = cx.state.context.prev @@ -371,7 +380,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse); } if (type == "function") return cont(functiondef); - if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); + if (type == "for") return cont(pushlex("form"), pushblockcontext, forspec, statement, popcontext, poplex); if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword" return cont(pushlex("form", type == "class" ? type : value), className, poplex) @@ -417,7 +426,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function parenExpr(type) { if (type != "(") return pass() - return cont(pushlex(")"), expression, expect(")"), poplex) + return cont(pushlex(")"), maybeexpression, expect(")"), poplex) } function expressionInner(type, value, noComma) { if (cx.state.fatArrowAt == cx.stream.start) { @@ -437,7 +446,6 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "{") return contCommasep(objprop, "}", null, maybeop); if (type == "quasi") return pass(quasi, maybeop); if (type == "new") return cont(maybeTarget(noComma)); - if (type == "import") return cont(expression); return cont(); } function maybeexpression(type) { @@ -455,7 +463,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); if (type == "operator") { if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me); - if (isTS && value == "<" && cx.stream.match(/^([^>]|<.*?>)*>\s*\(/, false)) + if (isTS && value == "<" && cx.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/, false)) return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me); if (value == "?") return cont(expression, expect(":"), expr); return cont(expr); @@ -475,7 +483,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function quasi(type, value) { if (type != "quasi") return pass(); if (value.slice(value.length - 2) != "${") return cont(quasi); - return cont(expression, continueQuasi); + return cont(maybeexpression, continueQuasi); } function continueQuasi(type) { if (type == "}") { @@ -601,7 +609,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } } function typeexpr(type, value) { - if (value == "keyof" || value == "typeof" || value == "infer") { + if (value == "keyof" || value == "typeof" || value == "infer" || value == "readonly") { cx.marked = "keyword" return cont(value == "typeof" ? expressionNoComma : typeexpr) } @@ -612,13 +620,19 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (value == "|" || value == "&") return cont(typeexpr) if (type == "string" || type == "number" || type == "atom") return cont(afterType); if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType) - if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType) + if (type == "{") return cont(pushlex("}"), typeprops, poplex, afterType) if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType, afterType) if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr) + if (type == "quasi") { return pass(quasiType, afterType); } } function maybeReturnType(type) { if (type == "=>") return cont(typeexpr) } + function typeprops(type) { + if (type.match(/[\}\)\]]/)) return cont() + if (type == "," || type == ";") return cont(typeprops) + return pass(typeprop, typeprops) + } function typeprop(type, value) { if (type == "variable" || cx.style == "keyword") { cx.marked = "property" @@ -631,6 +645,20 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return cont(expect("variable"), maybetypeOrIn, expect("]"), typeprop) } else if (type == "(") { return pass(functiondecl, typeprop) + } else if (!type.match(/[;\}\)\],]/)) { + return cont() + } + } + function quasiType(type, value) { + if (type != "quasi") return pass(); + if (value.slice(value.length - 2) != "${") return cont(quasiType); + return cont(typeexpr, continueQuasiType); + } + function continueQuasiType(type) { + if (type == "}") { + cx.marked = "string-2"; + cx.state.tokenize = tokenQuasi; + return cont(quasiType); } } function typearg(type, value) { @@ -757,11 +785,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } if (type == "variable" || cx.style == "keyword") { cx.marked = "property"; - return cont(isTS ? classfield : functiondef, classBody); + return cont(classfield, classBody); } - if (type == "number" || type == "string") return cont(isTS ? classfield : functiondef, classBody); + if (type == "number" || type == "string") return cont(classfield, classBody); if (type == "[") - return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody) + return cont(expression, maybetype, expect("]"), classfield, classBody) if (value == "*") { cx.marked = "keyword"; return cont(classBody); @@ -772,6 +800,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (value == "@") return cont(expression, classBody) } function classfield(type, value) { + if (value == "!") return cont(classfield) if (value == "?") return cont(classfield) if (type == ":") return cont(typeexpr, maybeAssign) if (value == "=") return cont(expressionNoComma) @@ -791,6 +820,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function afterImport(type) { if (type == "string") return cont(); if (type == "(") return pass(expression); + if (type == ".") return pass(maybeoperatorComma); return pass(importSpec, maybeMoreImports, maybeFrom); } function importSpec(type, value) { @@ -864,14 +894,14 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { }, indent: function(state, textAfter) { - if (state.tokenize == tokenComment) return CodeMirror.Pass; + if (state.tokenize == tokenComment || state.tokenize == tokenQuasi) return CodeMirror.Pass; if (state.tokenize != tokenBase) return 0; var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top // Kludge to prevent 'maybelse' from blocking lexical scope pops if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { var c = state.cc[i]; if (c == poplex) lexical = lexical.prev; - else if (c != maybeelse) break; + else if (c != maybeelse && c != popcontext) break; } while ((lexical.type == "stat" || lexical.type == "form") && (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) && @@ -908,8 +938,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { expressionAllowed: expressionAllowed, skipExpression: function(state) { - var top = state.cc[state.cc.length - 1] - if (top == expression || top == expressionNoComma) state.cc.pop() + parseJS(state, "atom", "atom", "true", new CodeMirror.StringStream("", 2, null)) } }; }); @@ -921,9 +950,10 @@ CodeMirror.defineMIME("text/ecmascript", "javascript"); CodeMirror.defineMIME("application/javascript", "javascript"); CodeMirror.defineMIME("application/x-javascript", "javascript"); CodeMirror.defineMIME("application/ecmascript", "javascript"); -CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); -CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); -CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true}); +CodeMirror.defineMIME("application/json", { name: "javascript", json: true }); +CodeMirror.defineMIME("application/x-json", { name: "javascript", json: true }); +CodeMirror.defineMIME("application/manifest+json", { name: "javascript", json: true }) +CodeMirror.defineMIME("application/ld+json", { name: "javascript", jsonld: true }); CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); diff --git a/dcScript/codemirror/mode/javascript/json-ld.html b/dcScript/codemirror/mode/javascript/json-ld.html new file mode 100644 index 0000000..d3dff2e --- /dev/null +++ b/dcScript/codemirror/mode/javascript/json-ld.html @@ -0,0 +1,72 @@ + + +CodeMirror: JSON-LD mode + + + + + + + + + + + + +
+

JSON-LD mode

+ + +
+ + + +

This is a specialization of the JavaScript mode.

+
diff --git a/dcScript/codemirror/mode/javascript/test.js b/dcScript/codemirror/mode/javascript/test.js new file mode 100644 index 0000000..a1bcf1f --- /dev/null +++ b/dcScript/codemirror/mode/javascript/test.js @@ -0,0 +1,521 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "javascript"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("locals", + "[keyword function] [def foo]([def a], [def b]) { [keyword var] [def c] [operator =] [number 10]; [keyword return] [variable-2 a] [operator +] [variable-2 c] [operator +] [variable d]; }"); + + MT("comma-and-binop", + "[keyword function](){ [keyword var] [def x] [operator =] [number 1] [operator +] [number 2], [def y]; }"); + + MT("destructuring", + "([keyword function]([def a], [[[def b], [def c] ]]) {", + " [keyword let] {[def d], [property foo]: [def c][operator =][number 10], [def x]} [operator =] [variable foo]([variable-2 a]);", + " [[[variable-2 c], [variable y] ]] [operator =] [variable-2 c];", + "})();"); + + MT("destructure_trailing_comma", + "[keyword let] {[def a], [def b],} [operator =] [variable foo];", + "[keyword let] [def c];"); // Parser still in good state? + + MT("class_body", + "[keyword class] [def Foo] {", + " [property constructor]() {}", + " [property sayName]() {", + " [keyword return] [string-2 `foo${][variable foo][string-2 }oo`];", + " }", + "}"); + + MT("class", + "[keyword class] [def Point] [keyword extends] [variable SuperThing] {", + " [keyword get] [property prop]() { [keyword return] [number 24]; }", + " [property constructor]([def x], [def y]) {", + " [keyword super]([string 'something']);", + " [keyword this].[property x] [operator =] [variable-2 x];", + " }", + "}"); + + MT("anonymous_class_expression", + "[keyword const] [def Adder] [operator =] [keyword class] [keyword extends] [variable Arithmetic] {", + " [property add]([def a], [def b]) {}", + "};"); + + MT("named_class_expression", + "[keyword const] [def Subber] [operator =] [keyword class] [def Subtract] {", + " [property sub]([def a], [def b]) {}", + "};"); + + MT("class_async_method", + "[keyword class] [def Foo] {", + " [property sayName1]() {}", + " [keyword async] [property sayName2]() {}", + "}"); + + MT("import", + "[keyword function] [def foo]() {", + " [keyword import] [def $] [keyword from] [string 'jquery'];", + " [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];", + "}"); + + MT("import_trailing_comma", + "[keyword import] {[def foo], [def bar],} [keyword from] [string 'baz']") + + MT("import_dynamic", + "[keyword import]([string 'baz']).[property then]") + + MT("import_dynamic", + "[keyword const] [def t] [operator =] [keyword import]([string 'baz']).[property then]") + + MT("const", + "[keyword function] [def f]() {", + " [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];", + "}"); + + MT("for/of", + "[keyword for]([keyword let] [def of] [keyword of] [variable something]) {}"); + + MT("for await", + "[keyword for] [keyword await]([keyword let] [def of] [keyword of] [variable something]) {}"); + + MT("generator", + "[keyword function*] [def repeat]([def n]) {", + " [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])", + " [keyword yield] [variable-2 i];", + "}"); + + MT("let_scoping", + "[keyword function] [def scoped]([def n]) {", + " { [keyword var] [def i]; } [variable-2 i];", + " { [keyword let] [def j]; [variable-2 j]; } [variable j];", + " [keyword if] ([atom true]) { [keyword const] [def k]; [variable-2 k]; } [variable k];", + "}"); + + MT("switch_scoping", + "[keyword switch] ([variable x]) {", + " [keyword default]:", + " [keyword let] [def j];", + " [keyword return] [variable-2 j]", + "}", + "[variable j];") + + MT("leaving_scope", + "[keyword function] [def a]() {", + " {", + " [keyword const] [def x] [operator =] [number 1]", + " [keyword if] ([atom true]) {", + " [keyword let] [def y] [operator =] [number 2]", + " [keyword var] [def z] [operator =] [number 3]", + " [variable console].[property log]([variable-2 x], [variable-2 y], [variable-2 z])", + " }", + " [variable console].[property log]([variable-2 x], [variable y], [variable-2 z])", + " }", + " [variable console].[property log]([variable x], [variable y], [variable-2 z])", + "}") + + MT("quotedStringAddition", + "[keyword let] [def f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];"); + + MT("quotedFatArrow", + "[keyword let] [def f] [operator =] [variable a] [operator +] [string '=>'] [operator +] [variable c];"); + + MT("fatArrow", + "[variable array].[property filter]([def a] [operator =>] [variable-2 a] [operator +] [number 1]);", + "[variable a];", // No longer in scope + "[keyword let] [def f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];", + "[variable c];"); + + MT("fatArrow_stringDefault", + "([def a], [def b] [operator =] [string 'x\\'y']) [operator =>] [variable-2 a] [operator +] [variable-2 b]") + + MT("spread", + "[keyword function] [def f]([def a], [meta ...][def b]) {", + " [variable something]([variable-2 a], [meta ...][variable-2 b]);", + "}"); + + MT("quasi", + "[variable re][string-2 `fofdlakj${][variable x] [operator +] ([variable re][string-2 `foo`]) [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]"); + + MT("quasi_no_function", + "[variable x] [operator =] [string-2 `fofdlakj${][variable x] [operator +] [string-2 `foo`] [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]"); + + MT("indent_statement", + "[keyword var] [def x] [operator =] [number 10]", + "[variable x] [operator +=] [variable y] [operator +]", + " [atom Infinity]", + "[keyword debugger];"); + + MT("indent_if", + "[keyword if] ([number 1])", + " [keyword break];", + "[keyword else] [keyword if] ([number 2])", + " [keyword continue];", + "[keyword else]", + " [number 10];", + "[keyword if] ([number 1]) {", + " [keyword break];", + "} [keyword else] [keyword if] ([number 2]) {", + " [keyword continue];", + "} [keyword else] {", + " [number 10];", + "}"); + + MT("indent_for", + "[keyword for] ([keyword var] [def i] [operator =] [number 0];", + " [variable-2 i] [operator <] [number 100];", + " [variable-2 i][operator ++])", + " [variable doSomething]([variable-2 i]);", + "[keyword debugger];"); + + MT("indent_c_style", + "[keyword function] [def foo]()", + "{", + " [keyword debugger];", + "}"); + + MT("indent_else", + "[keyword for] (;;)", + " [keyword if] ([variable foo])", + " [keyword if] ([variable bar])", + " [number 1];", + " [keyword else]", + " [number 2];", + " [keyword else]", + " [number 3];"); + + MT("indent_funarg", + "[variable foo]([number 10000],", + " [keyword function]([def a]) {", + " [keyword debugger];", + "};"); + + MT("indent_below_if", + "[keyword for] (;;)", + " [keyword if] ([variable foo])", + " [number 1];", + "[number 2];"); + + MT("indent_semicolonless_if", + "[keyword function] [def foo]() {", + " [keyword if] ([variable x])", + " [variable foo]()", + "}") + + MT("indent_semicolonless_if_with_statement", + "[keyword function] [def foo]() {", + " [keyword if] ([variable x])", + " [variable foo]()", + " [variable bar]()", + "}") + + MT("multilinestring", + "[keyword var] [def x] [operator =] [string 'foo\\]", + "[string bar'];"); + + MT("scary_regexp", + "[string-2 /foo[[/]]bar/];"); + + MT("indent_strange_array", + "[keyword var] [def x] [operator =] [[", + " [number 1],,", + " [number 2],", + "]];", + "[number 10];"); + + MT("param_default", + "[keyword function] [def foo]([def x] [operator =] [string-2 `foo${][number 10][string-2 }bar`]) {", + " [keyword return] [variable-2 x];", + "}"); + + MT( + "param_destructuring", + "[keyword function] [def foo]([def x] [operator =] [string-2 `foo${][number 10][string-2 }bar`]) {", + " [keyword return] [variable-2 x];", + "}"); + + MT("new_target", + "[keyword function] [def F]([def target]) {", + " [keyword if] ([variable-2 target] [operator &&] [keyword new].[keyword target].[property name]) {", + " [keyword return] [keyword new]", + " .[keyword target];", + " }", + "}"); + + MT("async", + "[keyword async] [keyword function] [def foo]([def args]) { [keyword return] [atom true]; }"); + + MT("async_assignment", + "[keyword const] [def foo] [operator =] [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; };"); + + MT("async_object", + "[keyword let] [def obj] [operator =] { [property async]: [atom false] };"); + + // async be highlighted as keyword and foo as def, but it requires potentially expensive look-ahead. See #4173 + MT("async_object_function", + "[keyword let] [def obj] [operator =] { [property async] [property foo]([def args]) { [keyword return] [atom true]; } };"); + + MT("async_object_properties", + "[keyword let] [def obj] [operator =] {", + " [property prop1]: [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; },", + " [property prop2]: [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; },", + " [property prop3]: [keyword async] [keyword function] [def prop3]([def args]) { [keyword return] [atom true]; },", + "};"); + + MT("async_arrow", + "[keyword const] [def foo] [operator =] [keyword async] ([def args]) [operator =>] { [keyword return] [atom true]; };"); + + MT("async_jquery", + "[variable $].[property ajax]({", + " [property url]: [variable url],", + " [property async]: [atom true],", + " [property method]: [string 'GET']", + "});"); + + MT("async_variable", + "[keyword const] [def async] [operator =] {[property a]: [number 1]};", + "[keyword const] [def foo] [operator =] [string-2 `bar ${][variable async].[property a][string-2 }`];") + + MT("bigint", "[number 1n] [operator +] [number 0x1afn] [operator +] [number 0o064n] [operator +] [number 0b100n];") + + MT("async_comment", + "[keyword async] [comment /**/] [keyword function] [def foo]([def args]) { [keyword return] [atom true]; }"); + + MT("indent_switch", + "[keyword switch] ([variable x]) {", + " [keyword default]:", + " [keyword return] [number 2]", + "}") + + MT("regexp_corner_case", + "[operator +]{} [operator /] [atom undefined];", + "[[[meta ...][string-2 /\\//] ]];", + "[keyword void] [string-2 /\\//];", + "[keyword do] [string-2 /\\//]; [keyword while] ([number 0]);", + "[keyword if] ([number 0]) {} [keyword else] [string-2 /\\//];", + "[string-2 `${][variable async][operator ++][string-2 }//`];", + "[string-2 `${]{} [operator /] [string-2 /\\//}`];") + + MT("return_eol", + "[keyword return]", + "{} [string-2 /5/]") + + MT("numeric separator", + "[number 123_456];", + "[number 0xdead_c0de];", + "[number 0o123_456];", + "[number 0b1101_1101];", + "[number .123_456e0_1];", + "[number 1E+123_456];", + "[number 12_34_56n];") + + MT("underscore property", + "[variable something].[property _property];", + "[variable something].[property _123];", + "[variable something].[property _for];", + "[variable _for];", + "[variable _123];") + + MT("private properties", + "[keyword class] [def C] {", + " [property #x] [operator =] [number 2];", + " [property #read]() {", + " [keyword return] [keyword this].[property #x]", + " }", + "}") + + var ts_mode = CodeMirror.getMode({indentUnit: 2}, "application/typescript") + function TS(name) { + test.mode(name, ts_mode, Array.prototype.slice.call(arguments, 1)) + } + + TS("typescript_extend_type", + "[keyword class] [def Foo] [keyword extends] [type Some][operator <][type Type][operator >] {}") + + TS("typescript_arrow_type", + "[keyword let] [def x]: ([variable arg]: [type Type]) [operator =>] [type ReturnType]") + + TS("typescript_class", + "[keyword class] [def Foo] {", + " [keyword public] [keyword static] [property main]() {}", + " [keyword private] [property _foo]: [type string];", + "}") + + TS("typescript_literal_types", + "[keyword import] [keyword *] [keyword as] [def Sequelize] [keyword from] [string 'sequelize'];", + "[keyword interface] [def MyAttributes] {", + " [property truthy]: [string 'true'] [operator |] [number 1] [operator |] [atom true];", + " [property falsy]: [string 'false'] [operator |] [number 0] [operator |] [atom false];", + "}", + "[keyword interface] [def MyInstance] [keyword extends] [type Sequelize].[type Instance] [operator <] [type MyAttributes] [operator >] {", + " [property rawAttributes]: [type MyAttributes];", + " [property truthy]: [string 'true'] [operator |] [number 1] [operator |] [atom true];", + " [property falsy]: [string 'false'] [operator |] [number 0] [operator |] [atom false];", + "}") + + TS("typescript_extend_operators", + "[keyword export] [keyword interface] [def UserModel] [keyword extends]", + " [type Sequelize].[type Model] [operator <] [type UserInstance], [type UserAttributes] [operator >] {", + " [property findById]: (", + " [variable userId]: [type number]", + " ) [operator =>] [type Promise] [operator <] [type Array] [operator <] { [property id], [property name] } [operator >>];", + " [property updateById]: (", + " [variable userId]: [type number],", + " [variable isActive]: [type boolean]", + " ) [operator =>] [type Promise] [operator <] [type AccountHolderNotificationPreferenceInstance] [operator >];", + " }") + + TS("typescript_interface_with_const", + "[keyword const] [def hello]: {", + " [property prop1][operator ?]: [type string];", + " [property prop2][operator ?]: [type string];", + "} [operator =] {};") + + TS("typescript_double_extend", + "[keyword export] [keyword interface] [def UserAttributes] {", + " [property id][operator ?]: [type number];", + " [property createdAt][operator ?]: [type Date];", + "}", + "[keyword export] [keyword interface] [def UserInstance] [keyword extends] [type Sequelize].[type Instance][operator <][type UserAttributes][operator >], [type UserAttributes] {", + " [property id]: [type number];", + " [property createdAt]: [type Date];", + "}"); + + TS("typescript_index_signature", + "[keyword interface] [def A] {", + " [[ [variable prop]: [type string] ]]: [type any];", + " [property prop1]: [type any];", + "}"); + + TS("typescript_generic_class", + "[keyword class] [def Foo][operator <][type T][operator >] {", + " [property bar]() {}", + " [property foo](): [type Foo] {}", + "}") + + TS("typescript_type_when_keyword", + "[keyword export] [keyword type] [type AB] [operator =] [type A] [operator |] [type B];", + "[keyword type] [type Flags] [operator =] {", + " [property p1]: [type string];", + " [property p2]: [type boolean];", + "};") + + TS("typescript_type_when_not_keyword", + "[keyword class] [def HasType] {", + " [property type]: [type string];", + " [property constructor]([def type]: [type string]) {", + " [keyword this].[property type] [operator =] [variable-2 type];", + " }", + " [property setType]({ [def type] }: { [property type]: [type string]; }) {", + " [keyword this].[property type] [operator =] [variable-2 type];", + " }", + "}") + + TS("typescript_function_generics", + "[keyword function] [def a]() {}", + "[keyword function] [def b][operator <][type IA] [keyword extends] [type object], [type IB] [keyword extends] [type object][operator >]() {}", + "[keyword function] [def c]() {}") + + TS("typescript_complex_return_type", + "[keyword function] [def A]() {", + " [keyword return] [keyword this].[property property];", + "}", + "[keyword function] [def B](): [type Promise][operator <]{ [[ [variable key]: [type string] ]]: [type any] } [operator |] [atom null][operator >] {", + " [keyword return] [keyword this].[property property];", + "}") + + TS("typescript_complex_type_casting", + "[keyword const] [def giftpay] [operator =] [variable config].[property get]([string 'giftpay']) [keyword as] { [[ [variable platformUuid]: [type string] ]]: { [property version]: [type number]; [property apiCode]: [type string]; } };") + + TS("typescript_keyof", + "[keyword function] [def x][operator <][type T] [keyword extends] [keyword keyof] [type X][operator >]([def a]: [type T]) {", + " [keyword return]") + + TS("typescript_new_typeargs", + "[keyword let] [def x] [operator =] [keyword new] [variable Map][operator <][type string], [type Date][operator >]([string-2 `foo${][variable bar][string-2 }`])") + + TS("modifiers", + "[keyword class] [def Foo] {", + " [keyword public] [keyword abstract] [property bar]() {}", + " [property constructor]([keyword readonly] [keyword private] [def x]) {}", + "}") + + TS("arrow prop", + "({[property a]: [def p] [operator =>] [variable-2 p]})") + + TS("generic in function call", + "[keyword this].[property a][operator <][type Type][operator >]([variable foo]);", + "[keyword this].[property a][operator <][variable Type][operator >][variable foo];") + + TS("type guard", + "[keyword class] [def Appler] {", + " [keyword static] [property assertApple]([def fruit]: [type Fruit]): [variable-2 fruit] [keyword is] [type Apple] {", + " [keyword if] ([operator !]([variable-2 fruit] [keyword instanceof] [variable Apple]))", + " [keyword throw] [keyword new] [variable Error]();", + " }", + "}") + + TS("type as variable", + "[variable type] [operator =] [variable x] [keyword as] [type Bar];"); + + TS("enum body", + "[keyword export] [keyword const] [keyword enum] [def CodeInspectionResultType] {", + " [def ERROR] [operator =] [string 'problem_type_error'],", + " [def WARNING] [operator =] [string 'problem_type_warning'],", + " [def META],", + "}") + + TS("parenthesized type", + "[keyword class] [def Foo] {", + " [property x] [operator =] [keyword new] [variable A][operator <][type B], [type string][operator |](() [operator =>] [type void])[operator >]();", + " [keyword private] [property bar]();", + "}") + + TS("abstract class", + "[keyword export] [keyword abstract] [keyword class] [def Foo] {}") + + TS("interface without semicolons", + "[keyword interface] [def Foo] {", + " [property greet]([def x]: [type int]): [type blah]", + " [property bar]: [type void]", + "}") + + var jsonld_mode = CodeMirror.getMode( + {indentUnit: 2}, + {name: "javascript", jsonld: true} + ); + function LD(name) { + test.mode(name, jsonld_mode, Array.prototype.slice.call(arguments, 1)); + } + + LD("json_ld_keywords", + '{', + ' [meta "@context"]: {', + ' [meta "@base"]: [string "http://example.com"],', + ' [meta "@vocab"]: [string "http://xmlns.com/foaf/0.1/"],', + ' [property "likesFlavor"]: {', + ' [meta "@container"]: [meta "@list"]', + ' [meta "@reverse"]: [string "@beFavoriteOf"]', + ' },', + ' [property "nick"]: { [meta "@container"]: [meta "@set"] },', + ' [property "nick"]: { [meta "@container"]: [meta "@index"] }', + ' },', + ' [meta "@graph"]: [[ {', + ' [meta "@id"]: [string "http://dbpedia.org/resource/John_Lennon"],', + ' [property "name"]: [string "John Lennon"],', + ' [property "modified"]: {', + ' [meta "@value"]: [string "2010-05-29T14:17:39+02:00"],', + ' [meta "@type"]: [string "http://www.w3.org/2001/XMLSchema#dateTime"]', + ' }', + ' } ]]', + '}'); + + LD("json_ld_fake", + '{', + ' [property "@fake"]: [string "@fake"],', + ' [property "@contextual"]: [string "@identifier"],', + ' [property "user@domain.com"]: [string "@graphical"],', + ' [property "@ID"]: [string "@@ID"]', + '}'); +})(); diff --git a/dcScript/codemirror/mode/javascript/typescript.html b/dcScript/codemirror/mode/javascript/typescript.html new file mode 100644 index 0000000..d0bc3ae --- /dev/null +++ b/dcScript/codemirror/mode/javascript/typescript.html @@ -0,0 +1,62 @@ + + +CodeMirror: TypeScript mode + + + + + + + + + + +
+

TypeScript mode

+ + +
+ + + +

This is a specialization of the JavaScript mode.

+
diff --git a/dcScript/codemirror/mode/xml/index.html b/dcScript/codemirror/mode/xml/index.html new file mode 100644 index 0000000..c0f5e84 --- /dev/null +++ b/dcScript/codemirror/mode/xml/index.html @@ -0,0 +1,61 @@ + + +CodeMirror: XML mode + + + + + + + + + +
+

XML mode

+
+ +

The XML mode supports these configuration parameters:

+
+
htmlMode (boolean)
+
This switches the mode to parse HTML instead of XML. This + means attributes do not have to be quoted, and some elements + (such as br) do not require a closing tag.
+
matchClosing (boolean)
+
Controls whether the mode checks that close tags match the + corresponding opening tag, and highlights mismatches as errors. + Defaults to true.
+
alignCDATA (boolean)
+
Setting this to true will force the opening tag of CDATA + blocks to not be indented.
+
+ +

MIME types defined: application/xml, text/html.

+
diff --git a/dcScript/codemirror/mode/xml/test.js b/dcScript/codemirror/mode/xml/test.js new file mode 100644 index 0000000..ab37611 --- /dev/null +++ b/dcScript/codemirror/mode/xml/test.js @@ -0,0 +1,51 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/5/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "xml"), mname = "xml"; + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), mname); } + + MT("matching", + "[tag&bracket <][tag top][tag&bracket >]", + " text", + " [tag&bracket <][tag inner][tag&bracket />]", + "[tag&bracket ]"); + + MT("nonmatching", + "[tag&bracket <][tag top][tag&bracket >]", + " [tag&bracket <][tag inner][tag&bracket />]", + " [tag&bracket ]"); + + MT("doctype", + "[meta ]", + "[tag&bracket <][tag top][tag&bracket />]"); + + MT("cdata", + "[tag&bracket <][tag top][tag&bracket >]", + " [atom ]", + "[tag&bracket ]"); + + // HTML tests + mode = CodeMirror.getMode({indentUnit: 2}, "text/html"); + + MT("selfclose", + "[tag&bracket <][tag html][tag&bracket >]", + " [tag&bracket <][tag link] [attribute rel]=[string stylesheet] [attribute href]=[string \"/foobar\"][tag&bracket >]", + "[tag&bracket ]"); + + MT("list", + "[tag&bracket <][tag ol][tag&bracket >]", + " [tag&bracket <][tag li][tag&bracket >]one", + " [tag&bracket <][tag li][tag&bracket >]two", + "[tag&bracket ]"); + + MT("valueless", + "[tag&bracket <][tag input] [attribute type]=[string checkbox] [attribute checked][tag&bracket />]"); + + MT("pThenArticle", + "[tag&bracket <][tag p][tag&bracket >]", + " foo", + "[tag&bracket <][tag article][tag&bracket >]bar"); + +})(); diff --git a/dcScript/codemirror/mode/xml/xml.js b/dcScript/codemirror/mode/xml/xml.js index 73c6e0e..701e151 100644 --- a/dcScript/codemirror/mode/xml/xml.js +++ b/dcScript/codemirror/mode/xml/xml.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/5/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -187,9 +187,13 @@ CodeMirror.defineMode("xml", function(editorConf, config_) { }; } + function lower(tagName) { + return tagName && tagName.toLowerCase(); + } + function Context(state, tagName, startOfLine) { this.prev = state.context; - this.tagName = tagName; + this.tagName = tagName || ""; this.indent = state.indented; this.startOfLine = startOfLine; if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent)) @@ -205,8 +209,8 @@ CodeMirror.defineMode("xml", function(editorConf, config_) { return; } parentTagName = state.context.tagName; - if (!config.contextGrabbers.hasOwnProperty(parentTagName) || - !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { + if (!config.contextGrabbers.hasOwnProperty(lower(parentTagName)) || + !config.contextGrabbers[lower(parentTagName)].hasOwnProperty(lower(nextTagName))) { return; } popContext(state); @@ -240,7 +244,7 @@ CodeMirror.defineMode("xml", function(editorConf, config_) { if (type == "word") { var tagName = stream.current(); if (state.context && state.context.tagName != tagName && - config.implicitlyClosed.hasOwnProperty(state.context.tagName)) + config.implicitlyClosed.hasOwnProperty(lower(state.context.tagName))) popContext(state); if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) { setStyle = "tag"; @@ -279,7 +283,7 @@ CodeMirror.defineMode("xml", function(editorConf, config_) { var tagName = state.tagName, tagStart = state.tagStart; state.tagName = state.tagStart = null; if (type == "selfcloseTag" || - config.autoSelfClosers.hasOwnProperty(tagName)) { + config.autoSelfClosers.hasOwnProperty(lower(tagName))) { maybePopContext(state, tagName); } else { maybePopContext(state, tagName); @@ -359,7 +363,7 @@ CodeMirror.defineMode("xml", function(editorConf, config_) { if (context.tagName == tagAfter[2]) { context = context.prev; break; - } else if (config.implicitlyClosed.hasOwnProperty(context.tagName)) { + } else if (config.implicitlyClosed.hasOwnProperty(lower(context.tagName))) { context = context.prev; } else { break; @@ -367,8 +371,8 @@ CodeMirror.defineMode("xml", function(editorConf, config_) { } } else if (tagAfter) { // Opening tag spotted while (context) { - var grabbers = config.contextGrabbers[context.tagName]; - if (grabbers && grabbers.hasOwnProperty(tagAfter[2])) + var grabbers = config.contextGrabbers[lower(context.tagName)]; + if (grabbers && grabbers.hasOwnProperty(lower(tagAfter[2]))) context = context.prev; else break; @@ -399,7 +403,7 @@ CodeMirror.defineMode("xml", function(editorConf, config_) { xmlCurrentContext: function(state) { var context = [] for (var cx = state.context; cx; cx = cx.prev) - if (cx.tagName) context.push(cx.tagName) + context.push(cx.tagName) return context.reverse() } }; diff --git a/dcScript/dcstore.xml b/dcScript/dcstore.xml new file mode 100644 index 0000000..b517a89 --- /dev/null +++ b/dcScript/dcstore.xml @@ -0,0 +1,13 @@ + + + + dcScript + 2.3.0 + Gvx + Add script for DC + https://github.com/Gvx-/dcScript/releases/download/v2.3.0/plugin-dcScript-2.3.0.zip + 2.24 + https://github.com/Gvx-/dcScript + https://forum.dotclear.org/viewtopic.php?id=48714 + + diff --git a/dcScript/inc/class.dcPluginHelper.php b/dcScript/inc/_dcPluginHelper/class.dcPluginHelper224.php similarity index 64% rename from dcScript/inc/class.dcPluginHelper.php rename to dcScript/inc/_dcPluginHelper/class.dcPluginHelper224.php index 23895a3..06d2c50 100644 --- a/dcScript/inc/class.dcPluginHelper.php +++ b/dcScript/inc/_dcPluginHelper/class.dcPluginHelper224.php @@ -1,11 +1,11 @@ - * @copyright © 2008-2020 Gvx + * @copyright © 2008-2022 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ @@ -13,18 +13,24 @@ if(!defined('NL')) { define('NL', "\n"); } # New Line - -if(!function_exists('getInstance')) { # get class instance in $core - function getInstance($plugin) { return $GLOBALS['core']->{$plugin}; } +if(!function_exists('getInstance')) { # get class instance in dcCore::app() + function getInstance($plugin) { return dcCore::app()->{$plugin}; } } /** - * dcPluginHelper216 + * dcPluginHelper224 */ -abstract class dcPluginHelper216 { +abstract class dcPluginHelper224 { - /** @var string version */ - const VERSION = '216-r2020.04.25'; # class version + /** @var string VERSION */ + const VERSION = '224-r2022.11.13'; # class version + + /** @var string FILE_DIR_SEPARATOR */ + const FILE_DIR_SEPARATOR = DIRECTORY_SEPARATOR; + /** @var string URL_DIR_SEPARATOR */ + const URL_DIR_SEPARATOR = '/'; + /** @var string ZIP_DIR_SEPARATOR */ + const ZIP_DIR_SEPARATOR = '/'; /** * setDefaultSettings @@ -35,7 +41,7 @@ abstract class dcPluginHelper216 { */ protected function setDefaultSettings() { # debug mode - $this->debugDisplay('Not default settings for this plugin.'); + $this->debugDisplay('Not default settings for '.$this->plugin_id.' ('.get_class($this).') plugin.'); } /** @@ -49,7 +55,7 @@ protected function setDefaultSettings() { */ protected function installActions($old_version) { # debug mode - $this->debugDisplay('Not install actions for this plugin.'); + $this->debugDisplay('Not install actions for '.$this->plugin_id.' ('.get_class($this).') plugin.'); } /** @@ -61,7 +67,7 @@ protected function installActions($old_version) { */ protected function uninstallActions() { # debug mode - $this->debugDisplay('Not uninstall actions for this plugin.'); + $this->debugDisplay('Not uninstall actions for '.$this->plugin_id.' ('.get_class($this).') plugin.'); return true; } @@ -73,25 +79,28 @@ protected function uninstallActions() { * @return void */ public function _config() { - if(!defined('DC_CONTEXT_ADMIN') || !$this->core->auth->check('admin', $this->core->blog->id)) { return; } + if(!defined('DC_CONTEXT_ADMIN') || !dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_ADMIN]), dcCore::app()->blog->id)) { return; } $scope = $this->configScope(); if (isset($_POST['save'])) { try { //$this->settings('enabled', !empty($_POST['enabled']), $scope); - $this->core->blog->triggerBlog(); - $this->core->notices->addSuccessNotice( __('Configuration successfully updated.')); + dcCore::app()->blog->triggerBlog(); + dcAdminNotices::addSuccessNotice( __('Configuration successfully updated.')); } catch(exception $e) { - //$this->core->error->add($e->getMessage()); - $this->core->error->add(__('Unable to save the configuration')); + //dcCore::app()->error->add($e->getMessage()); + dcCore::app()->error->add(__('Unable to save the configuration')); } if(!empty($_GET['redir']) && strpos($_GET['redir'], 'p='.$this->info('id')) === false) { - $this->core->error->add(__('Redirection not found')); - $this->core->adminurl->redirect('admin.home'); + dcCore::app()->error->add(__('Redirection not found')); + dcCore::app()->adminurl->redirect('admin.home'); } http::redirect($_REQUEST['redir']); } + + // TODO: HERE display + # debug mode - $this->debugDisplay('Not config page for this plugin.'); + $this->debugDisplay('Not config page for '.$this->plugin_id.' ('.get_class($this).') plugin.'); } /** @@ -104,25 +113,29 @@ public function _config() { public function index() { if(!defined('DC_CONTEXT_ADMIN')) { return; } if(!$this->settings('enabled') && is_file(path::real($this->info('root').'/_config.php'))) { - if($this->core->auth->check('admin', $this->core->blog->id)) { - $this->core->adminurl->redirect('admin.plugins', array( - 'module' => $this->info('id'),'conf' => 1, 'redir' => $this->core->adminurl->get($this->info('adminUrl')) + if(dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_ADMIN]), dcCore::app()->blog->id)) { + dcCore::app()->adminurl->redirect('admin.plugins', array( + 'module' => $this->info('id'),'conf' => 1, 'redir' => dcCore::app()->adminurl->get($this->info('adminUrl')) )); } else { - $this->core->notices->addNotice('message', sprintf(__('%s plugin is not configured.'), $this->info('name'))); - $this->core->adminurl->redirect('admin.home'); + dcAdminNotices::addMessageNotice(sprintf(__('%s plugin is not configured.'), $this->info('name'))); + dcCore::app()->adminurl->redirect('admin.home'); } } try { if (isset($_POST['save'])) { - // TODO HERE inputs check + // TODO: HERE inputs check } + /** @phpstan-ignore-next-line */ } catch(exception $e) { - //$this->core->error->add($e->getMessage()); - $this->core->error->add(__('Unable to save the code')); + //dcCore::app()->error->add($e->getMessage()); + dcCore::app()->error->add(__('Unable to save the code')); } + + // TODO: HERE display + # debug mode - $this->debugDisplay('Not index page for this plugin.'); + $this->debugDisplay('Not index page for '.$this->plugin_id.' ('.get_class($this).') plugin.'); } /** @@ -133,7 +146,6 @@ public function index() { * @return void */ protected function _prepend() { - global $__autoload; # common (public & admin) if(defined('DC_CONTEXT_ADMIN')) { @@ -145,6 +157,8 @@ protected function _prepend() { # public only } + # debug mode + $this->debugDisplay('Not _prepend actions for '.$this->plugin_id.' ('.get_class($this).') plugin.'); } /** @@ -158,7 +172,7 @@ public function _admin() { if(!defined('DC_CONTEXT_ADMIN')) { return; } # debug mode - $this->debugDisplay('Not _admin actions for this plugin.'); + $this->debugDisplay('Not _admin actions for '.$this->plugin_id.' ('.get_class($this).') plugin.'); } /** @@ -170,20 +184,8 @@ public function _admin() { */ public function _public() { - } - - /** - * _xmlrpc - * - * @todo overloaded - * - * @return void - */ - public function _xmlrpc() { - if(!defined('DC_CONTEXT_ADMIN')) { return; } - # debug mode - $this->debugDisplay('Not _xmlrpc actions for this plugin.'); + $this->debugDisplay('Not _public page for '.$this->plugin_id.' ('.get_class($this).') plugin.'); } /** @@ -195,11 +197,10 @@ public function _xmlrpc() { * @return void */ public function resources($path) { - global $__resources; /* - if(!isset($__resources['help']['dcScript-config'])) { $__resources['help']['dcScript-config'] = $path.'/help/config.html'; } - if(!isset($__resources['help']['dcScript-edit'])) { $__resources['help']['dcScript-edit'] = $path.'/help/edit.html'; } - if(!isset($__resources['help']['dcScript-warning'])) { $__resources['help']['dcScript-warning'] = $path.'/help/warning.html'; } + if(!isset(dcCore::app()->resources['help']['dcScript-config'])) { dcCore::app()->resources['help']['dcScript-config'] = $path.'/help/config.html'; } + if(!isset(dcCore::app()->resources['help']['dcScript-edit'])) { dcCore::app()->resources['help']['dcScript-edit'] = $path.'/help/edit.html'; } + if(!isset(dcCore::app()->resources['help']['dcScript-warning'])) { dcCore::app()->resources['help']['dcScript-warning'] = $path.'/help/warning.html'; } */ # debug mode @@ -212,7 +213,6 @@ public function resources($path) { protected $admin_url; # admin url plugin protected $icon_small; # small icon file protected $icon_large; # large icon file - protected $core; # dcCore instance private $debug_mode = false; # debug mode for plugin private $debug_log = false; # debug Log for plugin @@ -222,13 +222,11 @@ public function resources($path) { /** * __construct * - * @param object $core * @param string $id * * @return void */ - public function __construct($core, $id) { - $this->core =& $core; + public function __construct($id) { # set plugin id and admin url $this->plugin_id = $id; @@ -240,20 +238,20 @@ public function __construct($core, $id) { # start logfile $this->debugLog('START_DEBUG'); - $this->debugLog('Version', $this->core->getVersion($this->plugin_id)); + $this->debugLog('Version', dcCore::app()->getVersion($this->plugin_id)); $this->debugLog('Helper version', self::VERSION); $this->debugLog('Page', $_SERVER['REQUEST_URI']); # Set admin context if(defined('DC_CONTEXT_ADMIN')) { # register self url - $urls = $this->core->adminurl->dumpUrls(); - if(!array_key_exists('admin.self', $urls)) { + $urls = dcCore::app()->adminurl->dumpUrls(); + if(!$urls->offsetExists('admin.self')) { $url = http::getSelfURI(); $url = str_replace('?'.parse_url($url, PHP_URL_QUERY), '', $url); // delete query - $url = substr($url, 1 + strrpos($url, '/')); // keep page name + $url = substr($url, 1 + strrpos($url, self::URL_DIR_SEPARATOR)); // keep page name if(in_array($url, array_column((array)$urls, 'url'))) { // Register checked - $this->core->adminurl->register('admin.self', $url, (empty($_GET) ? array(): $_GET)); + dcCore::app()->adminurl->register('admin.self', $url, ($_GET ?: array())); } } @@ -262,7 +260,7 @@ public function __construct($core, $id) { $this->icon_large = $this->plugin_id.$this->info('_icon_large'); # uninstall plugin procedure - if($this->core->auth->isSuperAdmin()) { $this->core->addBehavior('pluginBeforeDelete', array($this, 'uninstall')); } + if(dcCore::app()->auth->isSuperAdmin()) { dcCore::app()->addBehavior('pluginBeforeDelete', array($this, 'uninstall')); } } # set default settings if empty @@ -283,30 +281,30 @@ public function __destruct() { # end logfile $this->debugLog('END_DEBUG'); } - + ### Admin functions ### /** * _install * - * @return void + * @return Boolean */ public final function _install() { - if(!defined('DC_CONTEXT_ADMIN')) { return; } + if(!defined('DC_CONTEXT_ADMIN')) { return; } /** @phpstan-ignore-line */ try { # check plugin versions $new_version = $this->info('version'); - $old_version = $this->core->getVersion($this->plugin_id); - if (version_compare($old_version, $new_version, '>=')) { return; } + $old_version = dcCore::app()->getVersion($this->plugin_id); + if (version_compare($old_version, $new_version, '>=')) { return; } /** @phpstan-ignore-line */ # specifics install actions $this->installActions($old_version); # valid install - $this->core->setVersion($this->plugin_id, $new_version); + dcCore::app()->setVersion($this->plugin_id, $new_version); $this->debugLog('Update', 'version '.$new_version); return true; } catch (Exception $e) { $this->debugDisplay('[Install] : '.$e->getMessage()); - $this->core->error->add($e->getMessage()); + dcCore::app()->error->add($e->getMessage()); } return false; } @@ -316,21 +314,21 @@ public final function _install() { * * @param object $plugin * - * @return void + * @return void */ public final function uninstall($plugin) { - $this->debugLog('uninstall', 'version '.$this->core->getVersion($this->plugin_id)); + $this->debugLog('uninstall', 'version '.dcCore::app()->getVersion($this->plugin_id)); # specifics uninstall actions if($plugin['id'] == $this->plugin_id) { if($this->uninstallActions()) { # clean DC_VAR if(self::getVarDir($this->plugin_id)) { files::deltree(self::getVarDir($this->plugin_id)); } # delete all users prefs - $this->core->auth->user_prefs->delWorkSpace($this->plugin_id); + dcCore::app()->auth->user_prefs->delWorkSpace($this->plugin_id); # delete all blogs settings - $this->core->blog->settings->delNamespace($this->plugin_id); + dcCore::app()->blog->settings->delNamespace($this->plugin_id); # delete version - $this->core->delVersion($this->plugin_id); + dcCore::app()->delVersion($this->plugin_id); } } } @@ -341,7 +339,7 @@ public final function uninstall($plugin) { * @return string */ protected final function configScope() { - return (isset($_POST['scope']) ? $_POST['scope'] : ($this->core->auth->isSuperAdmin() ? 'global' : 'default')); + return (isset($_POST['scope']) ? $_POST['scope'] : (dcCore::app()->auth->isSuperAdmin() ? 'global' : 'default')); } /** @@ -354,11 +352,12 @@ protected final function configScope() { */ protected function configBaseline($scope=null, $activate=true) { $html = ''; - if($this->core->auth->isSuperAdmin()) { + if(dcCore::app()->auth->isSuperAdmin()) { if(empty($scope)) { $scope = $this->configScope(); } - $html .= '

+ $html .= ' +

  '.__('Select the blog in which parameters apply').' @@ -386,44 +385,43 @@ protected function configBaseline($scope=null, $activate=true) { * * @param string $menu * - * @return void + * @return object $this */ - public function adminMenu($menu='Plugins') { - if(!defined('DC_CONTEXT_ADMIN')) { return; } - global $_menu; - if(array_key_exists($menu, $_menu)) { - $_menu[$menu]->addItem( + public function adminMenu($menu=dcAdmin::MENU_PLUGINS) { + if(!defined('DC_CONTEXT_ADMIN')) { return; } /** @phpstan-ignore-line */ + if(dcCore::app()->menu->offsetExists($menu)) { + dcCore::app()->menu[$menu]->addItem( html::escapeHTML(__($this->info('name'))), # Item menu - $this->core->adminurl->get($this->admin_url), # Page admin url + dcCore::app()->adminurl->get($this->admin_url), # Page admin url dcPage::getPF($this->icon_small), # Icon menu preg_match( # Pattern url - '/'.$this->core->adminurl->get($this->admin_url).'(&.*)?$/', + self::URL_DIR_SEPARATOR.dcCore::app()->adminurl->get($this->admin_url).'(&.*)?$/', $_SERVER['REQUEST_URI'] ), - $this->core->auth->check($this->info('permissions'), $this->core->blog->id) # Permissions minimum + dcCore::app()->auth->check($this->info('permissions'), dcCore::app()->blog->id) # Permissions minimum ); } else { $this->debugDisplay('menu not present.'); - throw new ErrorException(sprinf(__('%s menu not present.'), $menu), 0, E_USER_NOTICE, __FILE__, __LINE__); + throw new ErrorException(sprintf(__('%s menu not present.'), $menu), 0, E_USER_NOTICE, __FILE__, __LINE__); } + return $this; } /** - * adminDashboardFavs + * adminDashboardFavsV2 * - * @param object $core * @param object $favs * - * @return void + * @return void */ - public function adminDashboardFavs($core, $favs) { + public function adminDashboardFavsV2($favs) { if(!defined('DC_CONTEXT_ADMIN')) { return; } $favs->register($this->plugin_id, array( - 'title' => $core->plugins->moduleInfo($this->plugin_id, 'name'), - 'url' => $core->adminurl->get($this->admin_url), + 'title' => dcCore::app()->plugins->moduleInfo($this->plugin_id, 'name'), + 'url' => dcCore::app()->adminurl->get($this->admin_url), 'small-icon' => dcPage::getPF($this->icon_small), 'large-icon' => dcPage::getPF($this->icon_large), - 'permissions' => $core->plugins->moduleInfo($this->plugin_id, 'permissions') + 'permissions' => dcCore::app()->plugins->moduleInfo($this->plugin_id, 'permissions') )); } @@ -436,7 +434,7 @@ public function adminDashboardFavs($core, $favs) { */ protected function adminBaseline($items=array()) { if(empty($items)) { $items = array( $this->info('name') => ''); } - return dcPage::breadcrumb(array_merge(array(html::escapeHTML($this->core->blog->name) => ''), $items)).$this->core->notices->getNotices()."\n"; + return dcPage::breadcrumb(array_merge(array(html::escapeHTML(dcCore::app()->blog->name) => ''), $items)).dcAdminNotices::getNotices().NL; } /** @@ -445,7 +443,7 @@ protected function adminBaseline($items=array()) { * @return string */ public function adminFooterInfo() { - if(!defined('DC_CONTEXT_ADMIN')) { return; } + if(!defined('DC_CONTEXT_ADMIN')) { return; } /** @phpstan-ignore-line */ $support = $this->info('support'); $details = $this->info('details'); return '

@@ -495,7 +493,7 @@ protected static function widgetFooter(&$w, $context=true, $class='') { * @param object $w * @param string $id * @param string $name - * @param callback $callback + * @param callable $callback * @param mixed $help * @param string $title * @@ -518,9 +516,8 @@ protected static function widgetAddBasic(&$w, $id, $name, $callback, $help, $tit * @return string */ protected static function widgetRender($w, $content, $class='', $attr='') { - global $core; - if (($w->homeonly == 1 && $core->url->type != 'default') || ($w->homeonly == 2 && $core->url->type == 'default') || $w->offline || empty($content)) { - return; + if (($w->homeonly == 1 && dcCore::app()->url->type != 'default') || ($w->homeonly == 2 && dcCore::app()->url->type == 'default') || $w->offline || empty($content)) { + return; /** @phpstan-ignore-line */ } $content = ($w->title ? $w->renderTitle(html::escapeHTML($w->title)) : '').$content; return $w->renderDiv($w->content_only, trim(trim($class).' '.$w->class), trim($attr), $content); @@ -533,7 +530,7 @@ protected static function widgetRender($w, $content, $class='', $attr='') { * * @param string $key * @param mixed $value - * @param string $scope + * @param mixed $scope * * @return mixed */ @@ -541,15 +538,15 @@ public final function settings($key, $value=null, $scope='default') { if(is_null($value)) { try { if($scope == 'global' || $scope === true) { - $value = $this->core->blog->settings->{$this->plugin_id}->getGlobal($key); + $value = dcCore::app()->blog->settings->{$this->plugin_id}->getGlobal($key); $v = json_decode($value, true); return is_array($v) ? $v : $value; } elseif($scope == 'local') { - $value = $this->core->blog->settings->{$this->plugin_id}->getLocal($key); + $value = dcCore::app()->blog->settings->{$this->plugin_id}->getLocal($key); $v = json_decode($value, true); return is_array($v) ? $v : $value; } - $value = $this->core->blog->settings->{$this->plugin_id}->$key; + $value = dcCore::app()->blog->settings->{$this->plugin_id}->$key; $v = json_decode($value, true); return is_array($v) ? $v : $value; } catch(Exception $e) { @@ -557,14 +554,14 @@ public final function settings($key, $value=null, $scope='default') { return null; } } else { + $global = ($scope == 'global' || $scope === true); try { if(is_array($value) || is_object($value)) { $value = json_encode($value); } - $global = ($scope == 'global' || $scope === true); - $this->core->blog->settings->{$this->plugin_id}->put($key, $value, null, null, true, $global); + dcCore::app()->blog->settings->{$this->plugin_id}->put($key, $value, null, null, true, $global); } catch(Exception $e) { $this->debugDisplay('Blog settings write error (namespace not exist).('.$key.')'); - $this->core->blog->settings->addNamespace($this->plugin_id); - $this->core->blog->settings->{$this->plugin_id}->put($key, $value, null, null, true, $global); + dcCore::app()->blog->settings->addNamespace($this->plugin_id); + dcCore::app()->blog->settings->{$this->plugin_id}->put($key, $value, null, null, true, $global); } } } @@ -574,7 +571,7 @@ public final function settings($key, $value=null, $scope='default') { * * @param string $key * @param mixed $value - * @param string $scope + * @param mixed $scope * * @return mixed */ @@ -582,15 +579,15 @@ public final function userSettings($key, $value=null, $scope='default') { if(is_null($value)) { try { if($scope == 'global' || $scope === true) { - $value = $this->core->auth->user_prefs->{$this->plugin_id}->getGlobal($key); + $value = dcCore::app()->auth->user_prefs->{$this->plugin_id}->getGlobal($key); $v = json_decode($value, true); return is_array($v) ? $v : $value; } elseif($scope == 'local') { - $value = $this->core->auth->user_prefs->{$this->plugin_id}->getLocal($key); + $value = dcCore::app()->auth->user_prefs->{$this->plugin_id}->getLocal($key); $v = json_decode($value, true); return is_array($v) ? $v : $value; } - $value = $this->core->auth->user_prefs->{$this->plugin_id}->$key; + $value = dcCore::app()->auth->user_prefs->{$this->plugin_id}->$key; $v = json_decode($value, true); return is_array($v) ? $v : $value; } catch(Exception $e) { @@ -598,14 +595,14 @@ public final function userSettings($key, $value=null, $scope='default') { return null; } } else { + $global = ($scope == 'global' || $scope === true); try { if(is_array($value) || is_object($value)) { $value = json_encode($value); } - $global = ($scope == 'global' || $scope === true); - $this->core->auth->user_prefs->{$this->plugin_id}->put($key,$value, null, null, true, $global); + dcCore::app()->auth->user_prefs->{$this->plugin_id}->put($key,$value, null, null, true, $global); } catch(Exception $e) { $this->debugDisplay('User settings write error (namespace not exist).('.$key.')'); - $this->core->auth->user_prefs->addWorkSpace($this->plugin_id); - $this->core->auth->user_prefs->{$this->plugin_id}->put($key,$value, null, null, true, $global); + dcCore::app()->auth->user_prefs->addWorkSpace($this->plugin_id); + dcCore::app()->auth->user_prefs->{$this->plugin_id}->put($key,$value, null, null, true, $global); } } } @@ -615,12 +612,13 @@ public final function userSettings($key, $value=null, $scope='default') { * * @param mixed $key * - * @return void + * @return object $this */ protected final function settingDrop($key) { - $s = new dcNamespace($this->core, null, $this->plugin_id); + $s = new dcNamespace(dcCore::app(), null, $this->plugin_id); /** @phpstan-ignore-line */ $s->drop($key); unset($s); + return $this; } /** @@ -628,12 +626,14 @@ protected final function settingDrop($key) { * * @param mixed $key * - * @return void + * @return object $this */ protected final function userSettingDrop($key) { - $s = new dcWorkspace($this->core, $this->core->auth->userID(), $this->plugin_id); + //$s = new dcWorkspace(dcCore::app(), dcCore::app()->auth->userID(), $this->plugin_id); + $s = new dcWorkspace(dcCore::app()->auth->userID(), $this->plugin_id); $s->drop($key); unset($s); + return $this; } /** @@ -652,7 +652,7 @@ public final function info($item=null, $default=null) { } elseif($item == 'helperVersion') { return self::VERSION; } else { - $res = $this->core->plugins->moduleInfo($this->plugin_id, $item); + $res = dcCore::app()->plugins->moduleInfo($this->plugin_id, $item); return $res === null ? $default : $res; } } @@ -660,7 +660,7 @@ public final function info($item=null, $default=null) { /** * nextStep * - * @param string $step + * @param mixed $step * @param integer $delay * * @return void @@ -671,8 +671,8 @@ public function nextStep($step, $delay=0) { if($delay > 0 && ($timeout - $delay) < time()) { return; } # if timeout > next task delay if($delay < 0 && ($timeout + $delay) > time()) { return; } # if timeout - delay < now - # --BEHAVIOR-- beforeNextStep - if($this->core->callBehavior('beforeNextStep', $this->core, $this->plugin_id, $step) === false) { return; } + # --BEHAVIOR-- beforeNextStepV2 + if(dcCore::app()->callBehavior('beforeNextStepV2', $this->plugin_id, $step) === false) { return; } if(is_array($step)) { foreach($step as $k => $v) { $_GET[$k] = $v; } @@ -690,16 +690,16 @@ public function nextStep($step, $delay=0) { * @param string $dir * @param boolean $create * - * @return string + * @return mixed */ public static function getVarDir($dir='', $create=false) { $dir = trim($dir, '\\/'); - $var_dir = path::real(DC_VAR.(empty($dir) ? '' : '/'.$dir), false); - if(strpos($var_dir, path::real(DC_VAR, false)) === false) { $GLOBALS['core']->error->add(__('The folder is not in the var directory')); } + $var_dir = path::real(DC_VAR.(empty($dir) ? '' : self::FILE_DIR_SEPARATOR.$dir), false); + if(strpos($var_dir, path::real(DC_VAR, false)) === false) { dcCore::app()->error->add(__('The folder is not in the var directory')); } if(!is_dir($var_dir)) { if(!$create) { return false; } @files::makeDir($var_dir, true); - if(!is_dir($var_dir)) { $GLOBALS['core']->error->add(__('Creating a var directory failed')); } + if(!is_dir($var_dir)) { dcCore::app()->error->add(__('Creating a var directory failed')); } } return $var_dir; } @@ -715,7 +715,7 @@ public final function getVF($file) { if(defined('DC_CONTEXT_ADMIN')) { return dcPage::getVF($file); } else { - return $this->core->blog->getVF($file); + return dcCore::app()->blog->getVF($file); } } @@ -727,15 +727,16 @@ public final function getVF($file) { * @return string */ public final function jsLoad($src) { - if(is_file($this->info('root').'/'.ltrim($src, '/'))) { - $file = $this->plugin_id.'/'.ltrim($src, '/'); + if(is_file($this->info('root').self::FILE_DIR_SEPARATOR.ltrim($src, self::FILE_DIR_SEPARATOR))) { + $file = $this->plugin_id.self::URL_DIR_SEPARATOR.ltrim($src, self::URL_DIR_SEPARATOR); $version = $this->info('version'); if(defined('DC_CONTEXT_ADMIN')) { return dcPage::jsLoad(dcPage::getPF($file), $version); } else { - return dcUtils::jsLoad($this->core->blog->getPF($file), $version); + return dcUtils::jsLoad(dcCore::app()->blog->getPF($file), $version); } } + return ''; } /** @@ -748,8 +749,8 @@ public final function jsLoad($src) { * @return string */ public final function cssLoad($src, $media='all', $import=false) { - if(is_file($this->info('root').'/'.ltrim($src, '/'))) { - $file = $this->plugin_id.'/'.ltrim($src, '/'); + if(is_file($this->info('root').self::FILE_DIR_SEPARATOR.ltrim($src, self::FILE_DIR_SEPARATOR))) { + $file = $this->plugin_id.self::URL_DIR_SEPARATOR.ltrim($src, self::URL_DIR_SEPARATOR); $version = $this->info('version'); if(defined('DC_CONTEXT_ADMIN')) { if($import) { @@ -759,12 +760,13 @@ public final function cssLoad($src, $media='all', $import=false) { } } else { if($import) { - return ''.NL; + return ''.NL; } else { - return dcUtils::cssLoad($this->core->blog->getPF($file), $media, $version); + return dcUtils::cssLoad(dcCore::app()->blog->getPF($file), $media, $version); } } } + return ''; } /** @@ -791,13 +793,14 @@ public final function jsJson($vars) { * * @param string $msg * - * @return void + * @return object $this */ protected final function debugDisplay($msg) { if($this->debug_mode && !empty($msg)) { - if(defined('DC_CONTEXT_ADMIN')) { $this->core->notices->addWarningNotice('DEBUG - '.$this->plugin_id.' : '.$msg); } + if(defined('DC_CONTEXT_ADMIN')) { dcAdminNotices::addWarningNotice('DEBUG - '.$this->plugin_id.' : '.$msg); } $this->debugLog('[Debug display]', $msg); } + return $this; } /** @@ -806,7 +809,7 @@ protected final function debugDisplay($msg) { * @param string $text * @param mixed $value * - * @return void + * @return object $this */ public final function debugLog($text, $value=null) { if($this->debug_log && !empty($text)) { @@ -831,8 +834,9 @@ public final function debugLog($text, $value=null) { } else { $text .= ' :'.NL.print_r($value, true).NL.str_pad('END_VALUE', 66, '*'); } - @file_put_contents ($this->debug_logfile, NL.'['.date('YmdHis').'-'.$this->plugin_id.'-'.$this->core->blog->id.'] '.$text, FILE_APPEND); + @file_put_contents ($this->debug_logfile, NL.'['.date('YmdHis').'-'.$this->plugin_id.'-'.dcCore::app()->blog->id.'] '.$text, FILE_APPEND); } + return $this; } /** @@ -841,7 +845,7 @@ public final function debugLog($text, $value=null) { * @param mixed $filename * @param boolean $reset_file * - * @return void + * @return object $this */ public final function setDebugFilename($filename=null, $reset_file=false) { if(empty($filename)) { $filename = self::getVarDir('logs', true).'/log_'.$this->plugin_id.'.txt'; } @@ -849,7 +853,7 @@ public final function setDebugFilename($filename=null, $reset_file=false) { if(is_dir(dirname($filename))) { $this->debug_logfile = $filename; } else { - $this->debug_logfile = self::getVarDir('logs', true).'/'.basename($filename); + $this->debug_logfile = self::getVarDir('logs', true).self::FILE_DIR_SEPARATOR.basename($filename); } if($this->debug_log) { if($this->debug_log_reset && $reset_file && is_file($this->debug_logfile)) { @@ -858,6 +862,7 @@ public final function setDebugFilename($filename=null, $reset_file=false) { @file_put_contents ($this->debug_logfile, NL, FILE_APPEND); } } + return $this; } } diff --git a/dcScript/inc/class.dcScript.php b/dcScript/inc/class.dcScript.php index a76a640..1564dda 100644 --- a/dcScript/inc/class.dcScript.php +++ b/dcScript/inc/class.dcScript.php @@ -5,21 +5,21 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2022 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ if(!defined('DC_RC_PATH')) { return; } -if(!isset($__autoload['dcPluginHelper216'])) { $__autoload['dcPluginHelper216'] = dirname(__FILE__).'/class.dcPluginHelper.php'; } +if(Clearbricks::lib()->autoloadSource('dcPluginHelper224') == false) { Clearbricks::lib()->autoload(['dcPluginHelper224' => __DIR__ . '/_dcPluginHelper/class.dcPluginHelper224.php']); } define('DECRYPTION_PAGE', 'http://promenade.temporelle.free.fr/tools/decrypt.php'); __('dcScript'); // plugin name __('Add script for DC'); // description plugin -//class dcScript extends dcPluginHelper024b { -class dcScript extends dcPluginHelper216 { +//class dcScript extends dcPluginHelper224 { +class dcScript extends dcPluginHelper224 { ### Constants ### const MCRYPT = 'mcrypt'; @@ -34,9 +34,9 @@ class dcScript extends dcPluginHelper216 { * @return void */ public static function publicHeadContent($core, $_ctx) { - if(version_compare(PHP_VERSION, '7.2', '>=') && ($core->dcScript->settings('crypt_lib') != self::OPENSSL)) { return; } - $html = self::decrypt($core->dcScript->settings('header_code'), $core->dcScript->getCryptKey(), $core->dcScript->settings('crypt_lib')); - if($core->dcScript->settings('enabled') && $core->dcScript->settings('header_code_enabled') && !empty($html)) { + if(dcCore::app()->dcScript->settings('crypt_lib') != self::OPENSSL) { return; } + $html = self::decrypt(dcCore::app()->dcScript->settings('header_code'), dcCore::app()->dcScript->getCryptKey(), dcCore::app()->dcScript->settings('crypt_lib')); + if(dcCore::app()->dcScript->settings('enabled') && dcCore::app()->dcScript->settings('header_code_enabled') && !empty($html)) { echo "\n".$html."\n\n"; } } @@ -49,9 +49,9 @@ public static function publicHeadContent($core, $_ctx) { * @return void */ public static function publicFooterContent($core, $_ctx) { - if(version_compare(PHP_VERSION, '7.2', '>=') && ($core->dcScript->settings('crypt_lib') != self::OPENSSL)) { return; } - $html = self::decrypt($core->dcScript->settings('footer_code'), $core->dcScript->getCryptKey(), $core->dcScript->settings('crypt_lib')); - if($core->dcScript->settings('enabled') && $core->dcScript->settings('footer_code_enabled') && !empty($html)) { + if(dcCore::app()->dcScript->settings('crypt_lib') != self::OPENSSL) { return; } + $html = self::decrypt(dcCore::app()->dcScript->settings('footer_code'), dcCore::app()->dcScript->getCryptKey(), dcCore::app()->dcScript->settings('crypt_lib')); + if(dcCore::app()->dcScript->settings('enabled') && dcCore::app()->dcScript->settings('footer_code_enabled') && !empty($html)) { echo "\n".$html."\n\n"; } } @@ -67,16 +67,12 @@ public static function publicFooterContent($core, $_ctx) { public static function encrypt($str, $key, $cryptLib=self::OPENSSL) { global $core; $key = pack('H*', hash('sha256', $key)); - if($cryptLib == self::MCRYPT) { // REMOVED in PHP 7.2 - if(version_compare(PHP_VERSION, '7.2', '>=')) { throw new Exception(__('Encryption incompatible with PHP 7.2 and more')); } - $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND); - return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $str, MCRYPT_MODE_ECB, $iv))); - } elseif($cryptLib == self::OPENSSL) { + if($cryptLib == self::OPENSSL) { $ivlen = openssl_cipher_iv_length(self::OPENSSL_METHOD); $iv = openssl_random_pseudo_bytes($ivlen); return trim(base64_encode($iv.openssl_encrypt($str, self::OPENSSL_METHOD, $key, OPENSSL_RAW_DATA, $iv))); } else { // unknown cryptLib - return self::encrypt($str, $key, $core->dcScript->getCryptLib()); + return self::encrypt($str, $key, dcCore::app()->dcScript->getCryptLib()); } } @@ -88,19 +84,15 @@ public static function encrypt($str, $key, $cryptLib=self::OPENSSL) { * @param string $cryptLib * @return string */ - public static function decrypt($str, $key, $cryptLib=self::MCRYPT) { + public static function decrypt($str, $key, $cryptLib=self::OPENSSL) { global $core; $key = pack('H*', hash('sha256', $key)); - if($cryptLib == self::MCRYPT) { // REMOVED in PHP 7.2 - if(version_compare(PHP_VERSION, '7.2', '>=')) { throw new Exception(__('Encryption incompatible with PHP 7.2 and more')); } - $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND); - return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($str), MCRYPT_MODE_ECB, $iv)); - } elseif($cryptLib == self::OPENSSL) { + if($cryptLib == self::OPENSSL) { $ivlen = openssl_cipher_iv_length(self::OPENSSL_METHOD); $str = base64_decode($str); return trim(openssl_decrypt(substr($str, $ivlen), self::OPENSSL_METHOD, $key, OPENSSL_RAW_DATA, substr($str, 0, $ivlen))); } else { // unknown cryptLib - return self::decrypt($str, $key, $core->dcScript->getCryptLib()); + return self::decrypt($str, $key, dcCore::app()->dcScript->getCryptLib()); } } @@ -121,7 +113,7 @@ public function getCryptKey($salt=DC_MASTER_KEY) { */ Public function getCryptLib() { $lib = $this->settings('crypt_lib'); - return (empty($lib) ? (version_compare(PHP_VERSION, '7.2', '>=')? self::OPENSSL : self::MCRYPT) : $lib); + return (empty($lib) ? self::OPENSSL : $lib); } Public function debugGetinfos() { @@ -135,14 +127,14 @@ public function getCryptKey($salt=DC_MASTER_KEY) { protected function setDefaultSettings() { # create config plugin - $this->core->blog->settings->addNamespace($this->plugin_id); - $this->core->blog->settings->{$this->plugin_id}->put('enabled', false, 'boolean', __('Enable plugin'), false, true); - $this->core->blog->settings->{$this->plugin_id}->put('header_code_enabled', false, 'boolean', __('Enable header code'), false, true); - $this->core->blog->settings->{$this->plugin_id}->put('footer_code_enabled', false, 'boolean', __('Enable footer code'), false, true); - $this->core->blog->settings->{$this->plugin_id}->put('header_code', self::encrypt('', $this->getCryptKey()), 'string', __('Header code'), false, true); - $this->core->blog->settings->{$this->plugin_id}->put('footer_code', self::encrypt('', $this->getCryptKey()), 'string', __('Footer code'), false, true); - $this->core->blog->settings->{$this->plugin_id}->put('backup_ext', '.html.txt', 'string', __('Extension Backup Files'), false, true); - $this->core->blog->settings->{$this->plugin_id}->put('crypt_lib', self::OPENSSL, 'string', __('Encryption library'), false, true); // add v2.1.0 + dcCore::app()->blog->settings->addNamespace($this->plugin_id); + dcCore::app()->blog->settings->{$this->plugin_id}->put('enabled', false, 'boolean', __('Enable plugin'), false, true); + dcCore::app()->blog->settings->{$this->plugin_id}->put('header_code_enabled', false, 'boolean', __('Enable header code'), false, true); + dcCore::app()->blog->settings->{$this->plugin_id}->put('footer_code_enabled', false, 'boolean', __('Enable footer code'), false, true); + dcCore::app()->blog->settings->{$this->plugin_id}->put('header_code', self::encrypt('', $this->getCryptKey()), 'string', __('Header code'), false, true); + dcCore::app()->blog->settings->{$this->plugin_id}->put('footer_code', self::encrypt('', $this->getCryptKey()), 'string', __('Footer code'), false, true); + dcCore::app()->blog->settings->{$this->plugin_id}->put('backup_ext', '.html.txt', 'string', __('Extension Backup Files'), false, true); + dcCore::app()->blog->settings->{$this->plugin_id}->put('crypt_lib', self::OPENSSL, 'string', __('Encryption library'), false, true); // add v2.1.0 } protected function installActions($old_version) { @@ -152,12 +144,12 @@ protected function installActions($old_version) { # version < 2 if(version_compare($old_version, '2', '<')) { // /!\ timeout possible for a lot of blogs # upgrade global settings - $this->core->blog->settings->{$this->plugin_id}->dropAll(true); + dcCore::app()->blog->settings->{$this->plugin_id}->dropAll(true); $this->setDefaultSettings(); # upgrade all blogs settings - $rs = $this->core->getBlogs(); + $rs = dcCore::app()->getBlogs(); while ($rs->fetch()) { - $settings = new dcSettings($this->core, $rs->blog_id); + $settings = new dcSettings($rs->blog_id); $settings->addNamespace($this->plugin_id); $settings->{$this->plugin_id}->put('enabled', $settings->{$this->plugin_id}->get('enabled')); $settings->{$this->plugin_id}->put('header_code_enabled', $settings->{$this->plugin_id}->get('header_code_enabled')); @@ -167,15 +159,15 @@ protected function installActions($old_version) { $settings->{$this->plugin_id}->put('backup_ext', $settings->{$this->plugin_id}->get('backup_ext')); unset($settings); } - dcPage::addWarningNotice(__('Default settings update.')); + dcAdminNotices::addWarningNotice(__('Default settings update.')); } # version < 2.0.0-r0143 if(version_compare($old_version, '2.0.0-r0143', '<')) { // /!\ timeout possible for a lot of blogs # upgrade all blogs settings - $rs = $this->core->getBlogs(); + $rs = dcCore::app()->getBlogs(); while ($rs->fetch()) { - $settings = new dcSettings($this->core, $rs->blog_id); + $settings = new dcSettings($rs->blog_id); $settings->addNamespace($this->plugin_id); $settings->{$this->plugin_id}->put('header_code', self::encrypt(self::decrypt($settings->{$this->plugin_id}->get('header_code'), DC_MASTER_KEY), $this->getCryptKey())); $settings->{$this->plugin_id}->put('footer_code', self::encrypt(self::decrypt($settings->{$this->plugin_id}->get('footer_code'), DC_MASTER_KEY), $this->getCryptKey())); @@ -185,11 +177,11 @@ protected function installActions($old_version) { # version < 2.1.1-dev-r0001 if(version_compare($old_version, '2.1.1-dev-r0001', '<')) { // /!\ timeout possible for a lot of blogs - $this->core->blog->settings->{$this->plugin_id}->put('crypt_lib', self::OPENSSL, 'string', __('Encryption library'), false, true); + dcCore::app()->blog->settings->{$this->plugin_id}->put('crypt_lib', self::OPENSSL, 'string', __('Encryption library'), false, true); # upgrade all blogs settings - $rs = $this->core->getBlogs(); + $rs = dcCore::app()->getBlogs(); while ($rs->fetch()) { - $settings = new dcSettings($this->core, $rs->blog_id); + $settings = new dcSettings($rs->blog_id); $settings->addNamespace($this->plugin_id); if(version_compare(PHP_VERSION, '7.2', '<')) { $settings->{$this->plugin_id}->put('header_code', self::encrypt(self::decrypt($settings->{$this->plugin_id}->get('header_code'), $this->getCryptKey()), $this->getCryptKey(),self::OPENSSL)); @@ -206,49 +198,49 @@ protected function installActions($old_version) { public function index() { if(!defined('DC_CONTEXT_ADMIN')) { return; } - dcPage::check('dcScript.edit'); + dcPage::check(dcCore::app()->auth->makePermissions([dcScriptPerms::EDIT])); if(!$this->settings('enabled') && is_file(path::real($this->info('root').'/_config.php'))) { - if($this->core->auth->check('admin', $this->core->blog->id)) { - $this->core->adminurl->redirect('admin.plugins', array( - 'module' => $this->info('id'),'conf' => 1, 'redir' => $this->core->adminurl->get($this->info('adminUrl')) + if(dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_ADMIN]), dcCore::app()->blog->id)) { + dcCore::app()->adminurl->redirect('admin.plugins', array( + 'module' => $this->info('id'),'conf' => 1, 'redir' => dcCore::app()->adminurl->get($this->info('adminUrl')) )); } else { - $this->core->notices->addNotice('message', sprintf(__('%s plugin is not configured.'), $this->info('name'))); - $this->core->adminurl->redirect('admin.home'); + dcAdminNotices::addMessageNotice(sprintf(__('%s plugin is not configured.'), $this->info('name'))); + dcCore::app()->adminurl->redirect('admin.home'); } } if (!empty($_POST)) { try { # submit later (warning page) if (isset($_POST['later'])) { - $this->core->adminurl->redirect('admin.home'); + dcCore::app()->adminurl->redirect('admin.home'); } # submit convert (warning page) if (isset($_POST['convert'])) { $this->settings('header_code', dcScript::encrypt(trim($_POST['header_code']), $this->getCryptKey(), dcScript::OPENSSL)); $this->settings('footer_code', dcScript::encrypt(trim($_POST['footer_code']), $this->getCryptKey(), dcScript::OPENSSL)); $this->settings('crypt_lib', dcScript::OPENSSL); - $this->core->blog->triggerBlog(); - dcPage::addSuccessNotice(__('Code successfully updated.')); - $this->core->adminurl->redirect($this->info('adminUrl'), array(), '#tab-1'); + dcCore::app()->blog->triggerBlog(); + dcAdminNotices::addSuccessNotice(__('Code successfully updated.')); + dcCore::app()->adminurl->redirect($this->info('adminUrl'), array(), '#tab-1'); } # submit tab 1 (standard page) if (isset($_POST['update_header'])) { $this->settings('header_code', dcScript::encrypt(trim($_POST['header_code'])."\n", $this->getCryptKey(), dcScript::OPENSSL)); - $this->core->blog->triggerBlog(); - dcPage::addSuccessNotice(__('Code successfully updated.')); - $this->core->adminurl->redirect($this->info('adminUrl'), array(), '#tab-1'); + dcCore::app()->blog->triggerBlog(); + dcAdminNotices::addSuccessNotice(__('Code successfully updated.')); + dcCore::app()->adminurl->redirect($this->info('adminUrl'), array(), '#tab-1'); } # submit tab 2 (standard page) if (isset($_POST['update_footer'])) { $this->settings('footer_code', dcScript::encrypt(trim($_POST['footer_code'])."\n", $this->getCryptKey(), dcScript::OPENSSL)); - $this->core->blog->triggerBlog(); - dcPage::addSuccessNotice(__('Code successfully updated.')); - $this->core->adminurl->redirect($this->info('adminUrl'), array(), '#tab-2'); + dcCore::app()->blog->triggerBlog(); + dcAdminNotices::addSuccessNotice(__('Code successfully updated.')); + dcCore::app()->adminurl->redirect($this->info('adminUrl'), array(), '#tab-2'); } } catch(exception $e) { - //$this->core->error->add($e->getMessage()); - $this->core->error->add(__('Unable to save the code')); + //dcCore::app()->error->add($e->getMessage()); + dcCore::app()->error->add(__('Unable to save the code')); } } @@ -256,79 +248,23 @@ public function index() { try { # download code (standard page) if(isset($_GET['download']) && in_array($_GET['download'], array('header', 'footer'), true)) { - $filename = '"'.trim($this->core->blog->name).'_'.date('Y-m-d').'_'.$_GET['download'].'.'.trim($this->settings('backup_ext'),'.').'"'; + $filename = '"'.trim(dcCore::app()->blog->name).'_'.date('Y-m-d').'_'.$_GET['download'].'.'.trim($this->settings('backup_ext'),'.').'"'; header('Content-Disposition: attachment;filename='.$filename); header('Content-Type: text/plain; charset=UTF-8'); echo dcScript::decrypt($this->settings($_GET['download'].'_code'), $this->getCryptKey(), $this->getCryptLib()); exit; } } catch(exception $e) { - //$this->core->error->add($e->getMessage()); - $this->core->error->add(__('Unable to save the file')); + //dcCore::app()->error->add($e->getMessage()); + dcCore::app()->error->add(__('Unable to save the file')); } } - if(version_compare(PHP_VERSION, '7.2', '>=') && ($this->settings('crypt_lib') != dcScript::OPENSSL)) { - $this->indexWarning(); - } else { - $this->indexStandard(); - } - } - - private function indexWarning() { - echo ''.NL; - echo ''.NL; - echo ''.html::escapeHTML($this->info('name')).''.NL; - echo $this->cssLoad('/inc/css/index.css'); - echo $this->jsLoad('/inc/js/index_warning.js'); - dcPage::addNotice('message', __('See help for the procedure')); - echo ''.NL; - - echo ''.NL; - // Baseline - echo $this->adminBaseline(); - // datas - echo '

'.NL; - echo '

'.hash('sha256', $this->getCryptKey()).'

'.NL; - echo '

'.$this->settings('header_code').'

'.NL; - echo ''.NL; - echo '
'.NL; - // admin forms - echo '
'.NL; - echo '

'.__('Convert fields to new encryption format').'

'.NL; - echo '

'.NL; - echo ''.NL; - echo ''.NL; - echo ''.NL; - echo ''.__('Decryption page').''.NL; - echo '

'.NL; - echo - '
-

'.$this->core->formNonce().'

-

'.__('Header code').'

-

'.form::textArea('header_code',120,9,'','maximal',0,false,'placeholder="'.__('Paste the code here').'"').'

-

'.__('Footer code').'

-

'.form::textArea('footer_code',120,9,'','maximal',0,false,'placeholder="'.__('Paste the code here').'"').'

-

- - -

-
'.NL; - echo '
'.NL; - // Footer plugin - echo $this->adminFooterInfo(); - // helpBlock - dcPage::helpBlock('dcScript-warning'); - echo NL.''.NL; - echo ''.NL; - } - - private function indexStandard() { $header = html::escapeHTML(dcScript::decrypt($this->settings('header_code'), $this->getCryptKey(), $this->getCryptLib())); $footer = html::escapeHTML(dcScript::decrypt($this->settings('footer_code'), $this->getCryptKey(), $this->getCryptLib())); - $formAction = html::escapeHTML($this->core->adminurl->get($this->info('adminUrl'))); - $downloadHeader = $this->core->adminurl->get($this->info('adminUrl'), array('download' => 'header')); - $downloadFooter = $this->core->adminurl->get($this->info('adminUrl'), array('download' => 'footer')); + $formAction = html::escapeHTML(dcCore::app()->adminurl->get($this->info('adminUrl'))); + $downloadHeader = dcCore::app()->adminurl->get($this->info('adminUrl'), array('download' => 'header')); + $downloadFooter = dcCore::app()->adminurl->get($this->info('adminUrl'), array('download' => 'footer')); echo ''.NL; echo ''.NL; @@ -370,9 +306,9 @@ private function indexStandard() { echo '
-

'.$this->core->formNonce().'

+

'.dcCore::app()->formNonce().'

'.form::hidden('change_header', '')/*for check change in CodeMirror => jsConfirmClose()*/.'

-

'.form::textArea('header_code', 120, 25, $header."\n", 'maximal', 0).'

+

'.form::textArea('header_code', 120, 25, $header."\n", 'maximal', '0').'

@@ -384,9 +320,9 @@ private function indexStandard() { echo '

-

'.$this->core->formNonce().'

+

'.dcCore::app()->formNonce().'

'.form::hidden('change_footer', '')/*for check change in CodeMirror => jsConfirmClose()*/.'

-

'.form::textArea('footer_code', 120, 25, $footer."\n", 'maximal', 0).'

+

'.form::textArea('footer_code', 120, 25, $footer."\n", 'maximal', '0').'

@@ -404,23 +340,23 @@ private function indexStandard() { } public function _public() { - $this->core->addBehavior('publicHeadContent', array('dcScript', 'publicHeadContent')); - $this->core->addBehavior('publicFooterContent', array('dcScript', 'publicFooterContent')); + dcCore::app()->addBehavior('publicHeadContent', array('dcScript', 'publicHeadContent')); + dcCore::app()->addBehavior('publicFooterContent', array('dcScript', 'publicFooterContent')); } public function _admin() { if(!defined('DC_CONTEXT_ADMIN')) { return; } # define new permissions - $this->core->auth->setPermissionType('dcScript.edit',__('Edit public scripts')); + dcCore::app()->auth->setPermissionType(dcCore::app()->auth->makePermissions([dcScriptPerms::EDIT]), __('Edit public scripts')); # menu & dashboard - $this->core->addBehavior('adminDashboardFavorites', array($this, 'adminDashboardFavs')); + dcCore::app()->addBehavior('adminDashboardFavorites', array($this, 'adminDashboardFavs')); $this->adminMenu('System'); - if(!$this->core->auth->check('admin', $this->core->blog->id)) { return; } + if(!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_ADMIN]), dcCore::app()->blog->id)) { return; } # admin only - if(!$this->core->auth->isSuperAdmin()) { return; } + if(!dcCore::app()->auth->isSuperAdmin()) { return; } # super admin only } @@ -436,15 +372,15 @@ public function _config() { $this->settings('header_code_enabled', !empty($_POST['header_code_enabled'])); $this->settings('footer_code_enabled', !empty($_POST['footer_code_enabled'])); $this->settings('backup_ext', html::escapeHTML($_POST['backup'])); - $this->core->blog->triggerBlog(); - dcPage::addSuccessNotice(__('Configuration successfully updated.')); + dcCore::app()->blog->triggerBlog(); + dcAdminNotices::addSuccessNotice(__('Configuration successfully updated.')); } catch(exception $e) { - //$this->core->error->add($e->getMessage()); - $this->core->error->add(__('Unable to save the configuration')); + //dcCore::app()->error->add($e->getMessage()); + dcCore::app()->error->add(__('Unable to save the configuration')); } if(!empty($_GET['redir']) && strpos($_GET['redir'], 'p='.$this->info('id')) === false) { - $this->core->error->add(__('Redirection not found')); - $this->core->adminurl->redirect('admin.home'); + dcCore::app()->error->add(__('Redirection not found')); + dcCore::app()->adminurl->redirect('admin.home'); } http::redirect($_REQUEST['redir']); } @@ -497,9 +433,8 @@ public function _config() { public function resources($path) { if(!defined('DC_CONTEXT_ADMIN')) { return; } - global $__resources; - if(!isset($__resources['help']['dcScript-config'])) { $__resources['help']['dcScript-config'] = $path.'/help/config.html'; } - if(!isset($__resources['help']['dcScript-edit'])) { $__resources['help']['dcScript-edit'] = $path.'/help/edit.html'; } - if(!isset($__resources['help']['dcScript-warning'])) { $__resources['help']['dcScript-warning'] = $path.'/help/warning.html'; } + if(!isset(dcCore::app()->resources['help']['dcScript-config'])) { dcCore::app()->resources['help']['dcScript-config'] = $path.'/help/config.html'; } + if(!isset(dcCore::app()->resources['help']['dcScript-edit'])) { dcCore::app()->resources['help']['dcScript-edit'] = $path.'/help/edit.html'; } + if(!isset(dcCore::app()->resources['help']['dcScript-warning'])) { dcCore::app()->resources['help']['dcScript-warning'] = $path.'/help/warning.html'; } } } diff --git a/dcScript/inc/css/index.css b/dcScript/inc/css/index.css index 43a2ef1..fafc59d 100644 --- a/dcScript/inc/css/index.css +++ b/dcScript/inc/css/index.css @@ -4,7 +4,7 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2021 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ @@ -139,4 +139,4 @@ a.button { button.copy_done { color: green; -} \ No newline at end of file +} diff --git a/dcScript/inc/js/index.js b/dcScript/inc/js/index.js index 35aece5..04e0df2 100644 --- a/dcScript/inc/js/index.js +++ b/dcScript/inc/js/index.js @@ -4,7 +4,7 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2021 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ 'use strict'; @@ -105,4 +105,4 @@ document.addEventListener('DOMContentLoaded', function() { globalThis.scrollTo(0, 0); // Go to top }, 5); -}); \ No newline at end of file +}); diff --git a/dcScript/inc/js/index_warning.js b/dcScript/inc/js/index_warning.js index b8000eb..06c1e89 100644 --- a/dcScript/inc/js/index_warning.js +++ b/dcScript/inc/js/index_warning.js @@ -4,7 +4,7 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2021 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ 'use strict'; @@ -36,4 +36,4 @@ document.getElementById('copy_footer_code').addEventListener('click', function() { copy(document.getElementById('footer_code'), this); }); }); -}()); \ No newline at end of file +}()); diff --git a/dcScript/index.php b/dcScript/index.php index 846194d..ccf5ec1 100644 --- a/dcScript/index.php +++ b/dcScript/index.php @@ -5,10 +5,10 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2022 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ if(!defined('DC_CONTEXT_ADMIN')) { return; } -$core->dcScript->index(); +dcCore::app()->dcScript->index(); diff --git a/dcScript/locales/en/resources.php b/dcScript/locales/en/resources.php index 173c98d..e038cdd 100644 --- a/dcScript/locales/en/resources.php +++ b/dcScript/locales/en/resources.php @@ -5,10 +5,10 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2022 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ if(!defined('DC_CONTEXT_ADMIN')) { return; } -$core->dcScript->resources(dirname(__FILE__)); +$core->dcScript->resources(__DIR__); diff --git a/dcScript/locales/fr/resources.php b/dcScript/locales/fr/resources.php index 173c98d..e038cdd 100644 --- a/dcScript/locales/fr/resources.php +++ b/dcScript/locales/fr/resources.php @@ -5,10 +5,10 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2022 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ if(!defined('DC_CONTEXT_ADMIN')) { return; } -$core->dcScript->resources(dirname(__FILE__)); +$core->dcScript->resources(__DIR__); diff --git a/dcScript/phpstan.neon b/dcScript/phpstan.neon new file mode 100644 index 0000000..1d677f7 --- /dev/null +++ b/dcScript/phpstan.neon @@ -0,0 +1,132 @@ +parameters: + level: 5 + + paths: + - C:/wamp64/www/dc2-plugins-dev/dcScript + + scanFiles: + - C:/wamp64/www/dc2-unstable/index.php + + scanDirectories: + - C:/wamp64/www/dc2-unstable + + excludePaths: + - C:/wamp64/www/dc2-plugins-dev/dcScript/*/libs/* + + bootstrapFiles: + - C:/wamp64/www/dc2-plugins-dev/dcScript/bin/phpstan.bootstrap.php + + fileExtensions: + - php + - in + + checkMissingIterableValueType: false + checkGenericClassInNonGenericObjectType: false + reportUnmatchedIgnoredErrors: false + + ignoreErrors: + + # $core variable may not be defined (globally) + - message: '#Variable \$core might not be defined#' + path: * + + # $_lang variable may not be defined (globally) + - message: '#Variable \$_lang might not be defined#' + path: * + + # $p_url variable may not be defined (plugins) + - message: '#Variable \$p_url might not be defined#' + path: *.php + + # $__widgets variable not may be defined (plugins) + - message: '#Variable \$__widgets might not be defined#' + path: *.php + + # $__default_widgets variable may not be defined (plugins) + - message: '#Variable \$__default_widgets might not be defined#' + path: *.php + + # $this variable may not be defined (plugins/themes) + - message: '#Variable \$this might not be defined#' + paths: + - */_define.php + - */_install.php + - */_uninstall.php + + # $list variable may not be defined (plugins/themes) + - message: '#Variable \$list might not be defined#' + paths: + - */_config.php + - */index.php + + # $_menu variable may not be defined (plugins/themes) + - message: '#Variable \$_menu might not be defined#' + path: */_admin.php + + # record object and auto properties + - message: '#Access to an undefined property record::#' + path: * + + # dcCore object and auto properties + - message: '#Access to an undefined property dcCore::#' + path: * + + # dcRecord object and auto properties + - message: '#Access to an undefined property dcRecord::#' + path: * + + # dcWidgets object and auto properties + - message: '#Access to an undefined property dcWidgets::#' + path: * + + # xmlTag object and auto properties + - message : '#Access to an undefined property xmlTag::#' + path: * + + # xmlTag object methods + - message : '#Call to an undefined method xmlTag::#' + path: * + + # dcSettings object and auto properties + - message : '#Access to an undefined property dcSettings::#' + path: * + + # dcPrefs object and auto properties + - message : '#Access to an undefined property dcPrefs::#' + path: * + + # dbStruct object and auto properties + - message : '#Access to an undefined property dbStruct::#' + path: * + + # fileItem object and auto properties + - message : '#Access to an undefined property fileItem::#' + path: * + + # cursor object and auto properties + - message : '#Access to an undefined property cursor::#' + path: * + + # static record extensions + - message: '#Call to an undefined method record::#' + path: * + + # Intensive use of magic __set/__get/__call/__invoke causes theses wrong warnings + - message: '#Call to an undefined method form[a-zA-Z0-9\\_]+::#' + path: * + + # Intensive use of magic __set/__get/__call/__invoke causes theses wrong warnings + - message: '#Access to an undefined property form[a-zA-Z0-9\\_]+::#' + path: * + + # form<*>filters + - message: '#Access to an undefined property admin[a-zA-Z0-9\\_]+Filter::\$[a-zA-Z0-9\\_]+.#' + path: * + + # dcAdminfilters + - message: '#Access to an undefined property dcAdminFilter::\$[a-zA-Z0-9\\_]+.#' + path: * + + # adminMediaPage + - message: '#Access to an undefined property adminMediaPage::\$[a-zA-Z0-9\\_]+.#' + path: * diff --git a/dcScript/tools/decrypt.php b/dcScript/tools/decrypt.php index ef7939b..437cc2f 100644 --- a/dcScript/tools/decrypt.php +++ b/dcScript/tools/decrypt.php @@ -6,7 +6,7 @@ * @package Dotclear\plungin\dcScript * * @author Gvx - * @copyright © 2014-2020 Gvx + * @copyright © 2014-2022 Gvx * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ diff --git a/dcstore.xml b/dcstore.xml new file mode 100644 index 0000000..b517a89 --- /dev/null +++ b/dcstore.xml @@ -0,0 +1,13 @@ + + + + dcScript + 2.3.0 + Gvx + Add script for DC + https://github.com/Gvx-/dcScript/releases/download/v2.3.0/plugin-dcScript-2.3.0.zip + 2.24 + https://github.com/Gvx-/dcScript + https://forum.dotclear.org/viewtopic.php?id=48714 + +