openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit f59125d2f80eb00303f901a4ac977314f1b5337d
parent 9fbe31a5f313195716603504099b313fed5bc7cd
Author: dankert <openrat@jandankert.de>
Date:   Sat, 18 Dec 2021 03:47:23 +0100

New: Every ES6-Module should have a minified version for performance reasons. Bad: The Minifier "Jsqueeze" is unable to minify ES6-modules, so we had to implement a simple JS-Minifier which strips out all comments.

Diffstat:
Mdev-helper/update.sh | 2+-
Mmodules/cms/ui/action/index/IndexShowAction.class.php | 16++++++++++++++--
Mmodules/cms/ui/themes/ThemeCompiler.class.php | 186+++++++++----------------------------------------------------------------------
Mmodules/cms/ui/themes/default/html/views/index/show.php | 12++++++------
Mmodules/cms/ui/themes/default/html/views/index/show.tpl.src.xml | 12++++++------
Amodules/cms/ui/themes/default/script/Oquery.min.js | 228+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/cms/ui/themes/default/script/jquery-global.min.js | 43+++++++++++++++++++++++++++++++++++++++++++
Amodules/cms/ui/themes/default/script/openrat/api.min.js | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/cms/ui/themes/default/script/openrat/callback.min.js | 17+++++++++++++++++
Mmodules/cms/ui/themes/default/script/openrat/components.js | 20+++++++++++++-------
Amodules/cms/ui/themes/default/script/openrat/components.min.js | 19+++++++++++++++++++
Amodules/cms/ui/themes/default/script/openrat/dialog.min.js | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/cms/ui/themes/default/script/openrat/form.min.js | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/cms/ui/themes/default/script/openrat/init.min.js | 3+++
Mmodules/cms/ui/themes/default/script/openrat/navigator.js | 4+++-
Amodules/cms/ui/themes/default/script/openrat/navigator.min.js | 13+++++++++++++
Amodules/cms/ui/themes/default/script/openrat/notice.min.js | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmodules/cms/ui/themes/default/script/openrat/view.js | 2--
Amodules/cms/ui/themes/default/script/openrat/view.min.js | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmodules/cms/ui/themes/default/script/openrat/workbench.js | 16+++++++++++++++-
Amodules/cms/ui/themes/default/script/openrat/workbench.min.js | 574+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/cms/ui/themes/default/script/plugin/jquery-plugin-orAutoheight.min.js | 17+++++++++++++++++
Amodules/cms/ui/themes/default/script/plugin/jquery-plugin-orButton.min.js | 16++++++++++++++++
Amodules/cms/ui/themes/default/script/plugin/jquery-plugin-orLinkify.min.js | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/cms/ui/themes/default/script/plugin/jquery-plugin-orSearch.min.js | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/cms/ui/themes/default/script/plugin/jquery-plugin-orTree.min.js | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/cms/ui/themes/default/script/plugin/jquery-plugin-toggleAttr.min.js | 11+++++++++++
Mmodules/template_engine/components/html/component_editor/editor.js | 2+-
Amodules/template_engine/components/html/component_editor/editor.min.js | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amodules/template_engine/components/html/component_group/group.min.js | 6++++++
Amodules/template_engine/components/html/component_image/image.min.js | 0
Amodules/template_engine/components/html/component_link/link.min.js | 5+++++
Amodules/template_engine/components/html/component_qrcode/qrcode.min.js | 34++++++++++++++++++++++++++++++++++
Amodules/template_engine/components/html/component_table/table.min.js | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmodules/template_engine/components/html/component_upload/upload.js | 7+++----
Amodules/template_engine/components/html/component_upload/upload.min.js | 45+++++++++++++++++++++++++++++++++++++++++++++
Amodules/util/JSMinifier.class.php | 50++++++++++++++++++++++++++++++++++++++++++++++++++
37 files changed, 2145 insertions(+), 197 deletions(-)

diff --git a/dev-helper/update.sh b/dev-helper/update.sh @@ -82,7 +82,7 @@ function make_writable { lang ) chmod -v a+w ../modules/language ../modules/language/Language_*.php ../modules/language/Messages*;; xsd ) chmod -v a+w ../modules/template_engine/components/template.xsd ../modules/template_engine/components/components.ini;; css ) chmod -v a+w ../modules/cms/ui/themes/$theme/style/openrat*.css;; - js ) chmod -v a+w ../modules/cms/ui/themes/$theme/script/openrat*.js;; + js ) find ../modules/cms/ui/themes/$theme/script/ -type f -name "*.min.js" -exec chmod -v a+w {} \; ; find ../modules/template_engine/components/html/ -type f -name "*.min.js" -exec chmod -v a+w {} \; ;; tpl ) find ../modules/cms/ui/themes/$theme/html/views/ -type f -name "*.php" -exec chmod -v a+w {} \; ;; * ) echo "unknown type";exit;; esac diff --git a/modules/cms/ui/action/index/IndexShowAction.class.php b/modules/cms/ui/action/index/IndexShowAction.class.php @@ -53,8 +53,9 @@ class IndexShowAction extends IndexAction implements Method { $this->setTemplateVar('style',$style ); $this->setTemplateVar('scriptLink', $this->getScriptLink() ); - $this->setTemplateVar('scriptModuleLink',Startup::THEMES_DIR . 'default/script/openrat/init.js'); - $this->setTemplateVar('styleLink' , $this->getStyleLink() ); + $this->setTemplateVar('scriptModuleLink',$this->getScriptModuleLink() ); + $this->setTemplateVar('jsExt' ,(PRODUCTION?'.min.js':'.js') ); + $this->setTemplateVar('styleLink' , $this->getStyleLink() ); $this->setTemplateVar('themeStyleLink', Html::url('index','themestyle',0,['style'=>$style]) ); $this->setTemplateVar('manifestLink' , Html::url('index','manifest' ) ); @@ -108,12 +109,23 @@ class IndexShowAction extends IndexAction implements Method { * Gets JS file for displaying the UI. * * @return string + * @deprecated */ protected function getScriptLink() { return Startup::THEMES_DIR . 'default/'.(PRODUCTION?Theme::SCRIPT_MINIFIED_FILENAME:Theme::SCRIPT_FILENAME); } + /** + * Gets JS file for displaying the UI. + * + * @return string + */ + protected function getScriptModuleLink() + { + return Startup::THEMES_DIR . 'default/script/openrat/init.'.(PRODUCTION?'min.':'').'js'; + } + diff --git a/modules/cms/ui/themes/ThemeCompiler.class.php b/modules/cms/ui/themes/ThemeCompiler.class.php @@ -3,6 +3,7 @@ namespace cms\ui\themes; use util\FileUtils; +use util\JSMinifier; use util\JSqueeze; use logger\Logger; use template_engine\TemplateEngineInfo; @@ -93,16 +94,7 @@ class ThemeCompiler public function compileScripts() { - return; - - $combinedJsFile = __DIR__.'/default/'.Theme::SCRIPT_FILENAME; - $combinedJsFileMin = __DIR__.'/default/'.Theme::SCRIPT_MINIFIED_FILENAME; - - file_put_contents( $combinedJsFile ,''); - file_put_contents( $combinedJsFileMin,''); - $js = []; - $js[] = __DIR__.'/default/script/jquery'; // Jquery-Plugins $js[] = __DIR__.'/default/script/plugin/jquery-plugin-toggleAttr'; @@ -112,148 +104,20 @@ class ThemeCompiler $js[] = __DIR__.'/default/script/plugin/jquery-plugin-orTree'; $js[] = __DIR__.'/default/script/plugin/jquery-plugin-orAutoheight'; - // Codemirror Source Editor - - $js[] = __DIR__.'/../../../editor/codemirror/lib/codemirror'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/handlebars/handlebars'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/smalltalk/smalltalk'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/php/php'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/cobol/cobol'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/haskell/haskell'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/mathematica/mathematica'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/pug/pug'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/livescript/livescript'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/yaml-frontmatter/yaml-frontmatter'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/stylus/stylus'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/markdown/markdown'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/jsx/jsx'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/velocity/velocity'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/fortran/fortran'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/mirc/mirc'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/xquery/xquery'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/elm/elm'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/vhdl/vhdl'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/verilog/verilog'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/spreadsheet/spreadsheet'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/coffeescript/coffeescript'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/tiddlywiki/tiddlywiki'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/mumps/mumps'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/eiffel/eiffel'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/webidl/webidl'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/ebnf/ebnf'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/http/http'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/textile/textile'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/r/r'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/haml/haml'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/ecl/ecl'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/cypher/cypher'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/sieve/sieve'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/soy/soy'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/pig/pig'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/apl/apl'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/crystal/crystal'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/clike/clike'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/oz/oz'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/modelica/modelica'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/gherkin/gherkin'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/swift/swift'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/scheme/scheme'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/idl/idl'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/yaml/yaml'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/vue/vue'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/twig/twig'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/cmake/cmake'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/asciiarmor/asciiarmor'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/pegjs/pegjs'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/solr/solr'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/tiki/tiki'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/slim/slim'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/puppet/puppet'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/meta'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/go/go'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/commonlisp/commonlisp'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/rust/rust'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/powershell/powershell'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/stex/stex'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/q/q'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/htmlembedded/htmlembedded'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/d/d'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/protobuf/protobuf'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/mscgen/mscgen'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/django/django'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/toml/toml'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/yacas/yacas'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/dockerfile/dockerfile'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/python/python'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/vb/vb'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/octave/octave'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/tcl/tcl'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/clojure/clojure'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/sass/sass'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/gas/gas'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/sas/sas'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/julia/julia'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/fcl/fcl'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/tornado/tornado'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/asterisk/asterisk'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/sql/sql'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/gfm/gfm'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/mllike/mllike'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/rst/rst'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/ntriples/ntriples'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/sparql/sparql'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/properties/properties'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/rpm/rpm'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/htmlmixed/htmlmixed'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/xml/xml'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/ttcn-cfg/ttcn-cfg'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/ttcn/ttcn'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/z80/z80'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/brainfuck/brainfuck'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/forth/forth'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/nginx/nginx'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/javascript/javascript'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/pascal/pascal'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/haxe/haxe'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/perl/perl'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/factor/factor'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/smarty/smarty'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/vbscript/vbscript'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/dylan/dylan'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/asn.1/asn.1'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/ruby/ruby'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/nsis/nsis'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/css/css'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/haskell-literate/haskell-literate'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/mbox/mbox'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/dtd/dtd'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/erlang/erlang'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/turtle/turtle'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/troff/troff'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/jinja2/jinja2'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/diff/diff'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/dart/dart'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/shell/shell'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/lua/lua'; - $js[] = __DIR__.'/../../../editor/codemirror/mode/groovy/groovy'; - - - $js[] = __DIR__.'/../../../editor/simplemde/simplemde'; - $js[] = __DIR__.'/../../../editor/trumbowyg/trumbowyg'; - - // OpenRat internal JS - als letztes, damit die vorigen bereits geladen sind. - /* + $js[] = __DIR__.'/default/script/openrat/api'; $js[] = __DIR__.'/default/script/openrat/callback'; - $js[] = __DIR__.'/default/script/openrat/notice'; + $js[] = __DIR__.'/default/script/openrat/components'; $js[] = __DIR__.'/default/script/openrat/dialog'; - $js[] = __DIR__.'/default/script/openrat/view'; $js[] = __DIR__.'/default/script/openrat/form'; - $js[] = __DIR__.'/default/script/openrat/workbench'; - $js[] = __DIR__.'/default/script/openrat/navigator'; - $js[] = __DIR__.'/default/script/openrat/common'; $js[] = __DIR__.'/default/script/openrat/init'; - */ + $js[] = __DIR__.'/default/script/openrat/navigator'; + $js[] = __DIR__.'/default/script/openrat/notice'; + $js[] = __DIR__.'/default/script/openrat/view'; + $js[] = __DIR__.'/default/script/openrat/workbench'; + + $js[] = __DIR__.'/default/script/Oquery'; + $js[] = __DIR__.'/default/script/jquery-global'; // Komponentenbasiertes Javascript foreach ( TemplateEngineInfo::getComponentList() as $c) @@ -268,32 +132,22 @@ class ThemeCompiler $jsFileMin = $jsFile . '.min.js'; $jsFileNormal = $jsFile . '.js'; - if ( is_file($jsFileMin) ) + if( is_file($jsFileNormal) ) { - // A minified version exists, this is ok, we take it. - file_put_contents($combinedJsFile, '/* Include script: '.basename($jsFileMin).' */'."\n",FILE_APPEND); - file_put_contents($combinedJsFile , file_get_contents($jsFileMin)."\n",FILE_APPEND); - file_put_contents($combinedJsFileMin, file_get_contents($jsFileMin)."\n",FILE_APPEND); - - echo 'Copied content from minified source file '.$jsFileMin."\n"; - } - elseif( is_file($jsFileNormal) ) - { - // A normal script file exists. - file_put_contents($combinedJsFile, '/* Include script: '.basename($jsFileNormal).' */'."\n",FILE_APPEND); - file_put_contents($combinedJsFile , file_get_contents($jsFileNormal)."\n",FILE_APPEND); - // Minify.... - $jz = new JSqueeze(); - file_put_contents($combinedJsFileMin, $jz->squeeze(file_get_contents($jsFileNormal))."\n",FILE_APPEND); - - echo 'Copied content from source file '.$jsFileNormal."\n"; + $jz = new JSMinifier( + JSMinifier::FLAG_IMPORT_MIN_JS + + JSMinifier::FLAG_REMOVE_MULTILINE_COMMENT + + JSMinifier::FLAG_REMOVE_BLANK_LINES + + JSMinifier::FLAG_REMOVE_LINE_COMMENTS + + JSMinifier::FLAG_REMOVE_WHITESPACE ); + file_put_contents($jsFileMin, $jz->minify(file_get_contents($jsFileNormal))); + + echo 'Minified to '.$jsFileMin."\n"; } else { throw new \LogicException('Missing javascript: '.$jsFile ); } } - echo 'Created file '.$combinedJsFile."\n"; - echo 'Created file '.$combinedJsFileMin."\n"; } } diff --git a/modules/cms/ui/themes/default/html/views/index/show.php b/modules/cms/ui/themes/default/html/views/index/show.php @@ -7,12 +7,12 @@ <meta charset="<?php echo O::escapeHtml(''.@$charset.'') ?>" /><?php echo O::escapeHtml('') ?> <meta name="<?php echo O::escapeHtml('robots') ?>" content="<?php echo O::escapeHtml('noindex,nofollow') ?>" /><?php echo O::escapeHtml('') ?> <script type="<?php echo O::escapeHtml('module') ?>" src="<?php echo O::escapeHtml(''.@$scriptModuleLink.'') ?>"><?php echo O::escapeHtml('') ?></script> - <link rel="<?php echo O::escapeHtml('modulepreload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/script/openrat/workbench.js') ?>" /><?php echo O::escapeHtml('') ?> - <link rel="<?php echo O::escapeHtml('modulepreload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/script/openrat/callback.js') ?>" /><?php echo O::escapeHtml('') ?> - <link rel="<?php echo O::escapeHtml('modulepreload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/script/openrat/notice.js') ?>" /><?php echo O::escapeHtml('') ?> - <link rel="<?php echo O::escapeHtml('modulepreload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/script/openrat/view.js') ?>" /><?php echo O::escapeHtml('') ?> - <link rel="<?php echo O::escapeHtml('modulepreload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/script/openrat/dialog.js') ?>" /><?php echo O::escapeHtml('') ?> - <link rel="<?php echo O::escapeHtml('modulepreload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/script/openrat/navigator.js') ?>" /><?php echo O::escapeHtml('') ?> + <link rel="<?php echo O::escapeHtml('modulepreload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/script/openrat/workbench'.@$jsExt.'') ?>" /><?php echo O::escapeHtml('') ?> + <link rel="<?php echo O::escapeHtml('modulepreload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/script/openrat/callback'.@$jsExt.'') ?>" /><?php echo O::escapeHtml('') ?> + <link rel="<?php echo O::escapeHtml('modulepreload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/script/openrat/notice'.@$jsExt.'') ?>" /><?php echo O::escapeHtml('') ?> + <link rel="<?php echo O::escapeHtml('modulepreload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/script/openrat/view'.@$jsExt.'') ?>" /><?php echo O::escapeHtml('') ?> + <link rel="<?php echo O::escapeHtml('modulepreload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/script/openrat/dialog'.@$jsExt.'') ?>" /><?php echo O::escapeHtml('') ?> + <link rel="<?php echo O::escapeHtml('modulepreload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/script/openrat/navigator'.@$jsExt.'') ?>" /><?php echo O::escapeHtml('') ?> <link rel="<?php echo O::escapeHtml('preload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/font/oxygen-v7-latin-regular.woff2') ?>" as="<?php echo O::escapeHtml('font') ?>" type="<?php echo O::escapeHtml('font/woff2') ?>" crossorigin="<?php echo O::escapeHtml('anonymous') ?>" /><?php echo O::escapeHtml('') ?> <link rel="<?php echo O::escapeHtml('preload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/font/MaterialIcons-Regular.woff2') ?>" as="<?php echo O::escapeHtml('font') ?>" type="<?php echo O::escapeHtml('font/woff2') ?>" crossorigin="<?php echo O::escapeHtml('anonymous') ?>" /><?php echo O::escapeHtml('') ?> <link rel="<?php echo O::escapeHtml('preload') ?>" href="<?php echo O::escapeHtml('./modules/cms/ui/themes/default/font/source-code-pro-v8-latin-regular.woff2') ?>" as="<?php echo O::escapeHtml('font') ?>" type="<?php echo O::escapeHtml('font/woff2') ?>" crossorigin="<?php echo O::escapeHtml('anonymous') ?>" /><?php echo O::escapeHtml('') ?> diff --git a/modules/cms/ui/themes/default/html/views/index/show.tpl.src.xml b/modules/cms/ui/themes/default/html/views/index/show.tpl.src.xml @@ -15,12 +15,12 @@ <meta name="robots" content="noindex,nofollow"/> <script type="module" src="${scriptModuleLink}" /> <!-- preloading scripts as modules --> - <link rel="modulepreload" href="./modules/cms/ui/themes/default/script/openrat/workbench.js"/> - <link rel="modulepreload" href="./modules/cms/ui/themes/default/script/openrat/callback.js"/> - <link rel="modulepreload" href="./modules/cms/ui/themes/default/script/openrat/notice.js"/> - <link rel="modulepreload" href="./modules/cms/ui/themes/default/script/openrat/view.js"/> - <link rel="modulepreload" href="./modules/cms/ui/themes/default/script/openrat/dialog.js"/> - <link rel="modulepreload" href="./modules/cms/ui/themes/default/script/openrat/navigator.js"/> + <link rel="modulepreload" href="./modules/cms/ui/themes/default/script/openrat/workbench${jsExt}"/> + <link rel="modulepreload" href="./modules/cms/ui/themes/default/script/openrat/callback${jsExt}"/> + <link rel="modulepreload" href="./modules/cms/ui/themes/default/script/openrat/notice${jsExt}"/> + <link rel="modulepreload" href="./modules/cms/ui/themes/default/script/openrat/view${jsExt}"/> + <link rel="modulepreload" href="./modules/cms/ui/themes/default/script/openrat/dialog${jsExt}"/> + <link rel="modulepreload" href="./modules/cms/ui/themes/default/script/openrat/navigator${jsExt}"/> <!-- preloading fonts --> <link rel="preload" href="./modules/cms/ui/themes/default/font/oxygen-v7-latin-regular.woff2" as="font" type="font/woff2" crossorigin="anonymous"/> <link rel="preload" href="./modules/cms/ui/themes/default/font/MaterialIcons-Regular.woff2" as="font" type="font/woff2" crossorigin="anonymous"/> diff --git a/modules/cms/ui/themes/default/script/Oquery.min.js b/modules/cms/ui/themes/default/script/Oquery.min.js @@ -0,0 +1,227 @@ +let query = function (selector ) { +if ( typeof selector === 'string' ) +return query.createQuery( document.querySelectorAll(selector) ); +else if ( selector instanceof HTMLElement ) +return query.createQuery([selector] ); +else if ( selector instanceof OQuery ) +return selector; +else +return query.createQuery( [] ); +} +query.createQuery = function(nodeList ) { +return new OQuery( nodeList ); +} +query.create = function(tagName ) { +return query.createQuery( [document.createElement( tagName )] ); +}; +query.id = function(id ) { +let el = document.getElementById( id ); +if ( el ) +return query.createQuery( [el] ); +else +return query.createQuery( [] ); +}; +query.one = function(selector ) { +return query.createQuery( [document.querySelector( selector )] ); +}; +query.extend = function() { +for(let i=1; i<arguments.length; i++) +for(let key in arguments[i]) +if(arguments[i].hasOwnProperty(key)) +arguments[0][key] = arguments[i][key]; +return arguments[0]; +} +export default query; +export class OQuery { +static fn = OQuery.prototype; +createNew(nodeList) { +return new OQuery(nodeList) +}; +constructor( nodeList ) { +this.nodes = Array.isArray(nodeList) ? nodeList : Array.from(nodeList) +} +get( idx ) { +return this.nodes[idx]; +} +first() { +return this.createNew( this.nodes.length > 0 ? [this.nodes[0]] : [] ); +}; +parent() { +return this.createNew( this.nodes.map(node => node.parentNode ).filter( node => node !== null ) ); +}; +closest( selector ) { +return this.createNew( this.nodes.map(node => node.closest( selector ) ).filter( node => node !== null ) ); +}; +children( selector ) { +let result = []; +for( let node of this.nodes ) +result = result.concat( Array.from(node.children).filter( node => selector ? node.matches(selector) : true ) ); +return this.createNew( result ); +}; +find(selector) { +let result = []; +for( let node of this.nodes ) +result = result.concat( Array.from(node.querySelectorAll(selector)) ); +return this.createNew( result ); +}; +text( value ) { +if ( typeof value !== 'undefined' ) { +this.nodes.forEach(node => node.textContent = value ); +return this; +} +else { +return this.nodes[0].textContent; +} +}; +addClass( name ) { +this.nodes.forEach(node => node.classList.add( name ) ); +return this; +}; +removeClass ( name ) { +this.nodes.forEach( +node => node.classList.remove( name ) +); +return this; +}; +hasClass( name ) { +for( let node of this.nodes ) +if ( node.classList.contains( name ) ) +return true; +return false; +}; +toggleClass( name ) { +if ( this.hasClass( name ) ) +this.removeClass( name ); +else +this.addClass( name ); +return this; +}; +remove() { +this.nodes.forEach(node => node.remove() ); +return this; +}; +click ( handler ) { +this.on( 'click',handler ); +return this; +}; +dblclick ( handler ) { +this.on( 'dblclick',handler ); +return this; +}; +mouseover( handler ) { +this.on( 'mouseover',handler ); +return this; +}; +keypress( handler ) { +this.on( 'keypress',handler ); +return this; +}; +keyup( handler ) { +this.on( 'keyup',handler ); +return this; +}; +submit( handler ) { +this.on( 'submit',handler ); +return this; +} +change( handler ) { +this.on( 'change',handler ) +return this; +} +input( handler ) { +this.on( 'input',handler ) +return this; +} +on ( event,handler ) { +if ( typeof handler !== 'undefined') +this.nodes.forEach(node => node.addEventListener( event,handler.bind(node) ) ); +else +this.nodes.forEach(node => node.dispatchEvent( new Event(event) ) ); +return this; +}; +each( handler ) { +let idx = -1; +for( let node of this.nodes ) +if ( handler.call(node,idx,node) === false ) +break; +return this; +} +hide() { +this.nodes.forEach(node => node.style.display = 'none' ); +return this; +} +show() { +this.nodes.forEach(node => node.style.display = '' ); +return this; +} +append( el ) { +this.nodes.forEach(node => el.nodes.forEach(elnode => node.appendChild(elnode) ) ); +return this; +} +appendTo( el ) { +let to = query( el ); +to.append( this ) +return this; +} +attr( name,value ) { +if ( typeof value === 'undefined' ) +return this.nodes.length > 0 ? this.nodes[0].getAttribute(name) : ''; +this.nodes.forEach(node => node.setAttribute(name,value) ); +return this; +} +data( name,value) { +if ( typeof value === 'undefined' ) +if ( typeof name === 'undefined' ) +return this.nodes.length > 0 ? this.nodes[0].dataset : {}; +else +return this.nodes.length > 0 ? this.nodes[0].dataset[name] : null; +this.nodes.forEach(node => node.dataset[name] = value ); +return this; +} +html( value ) { +if ( typeof value === 'undefined') +return this.nodes.length > 0 ? this.nodes[0].innerHTML : ''; +this.nodes.forEach(node => node.innerHTML = value ); +return this; +} +val( value = null ) { +if ( value !== null ) { +this.nodes.forEach(node => node.value = value ); +return this; +} +else +return this.nodes.length > 0 ? this.nodes[0].value : ''; +} +empty() { +this.nodes.forEach(node => { +while (node.firstChild) { +node.removeChild(node.firstChild); +} +} ); +return this; +} +is( selector ) { +for( let node of this.nodes ) +if ( node.matches(selector) ) +return true; +return false; +} +toArray() { +return this.nodes; +} +eq( index ) { +return this.createNew( [ this.nodes[index] ] ); +} +index() { +if ( this.nodes.length == 0 ) +return -1; +let node = this.nodes[0]; +let children = node.parentNode.childNodes; +let num = 0; +for (let i=0; i<children.length; i++) { +if ( children[i] == node) return num; +if ( children[i].nodeType==1) num++; +} +return -1; +} +} +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/jquery-global.min.js b/modules/cms/ui/themes/default/script/jquery-global.min.js @@ -0,0 +1,42 @@ +import query, {OQuery} from './Oquery.min.js'; +import autoheight from './plugin/jquery-plugin-orAutoheight.min.js'; +import button from './plugin/jquery-plugin-orButton.min.js'; +import linkify from './plugin/jquery-plugin-orLinkify.min.js'; +import search from './plugin/jquery-plugin-orSearch.min.js'; +import tree from './plugin/jquery-plugin-orTree.min.js'; +import toggleAttr from './plugin/jquery-plugin-toggleAttr.min.js'; +query.createQuery = (nodeList) => new CMSQuery(nodeList); +export default query; +class CMSQuery extends OQuery { +createNew(nodeList) { +return new CMSQuery(nodeList); +} +static classPrefix = 'or-'; +addClass( styleClass ) { +return super.addClass( CMSQuery.classPrefix + styleClass ) +} +removeClass( styleClass ) { +return super.removeClass( CMSQuery.classPrefix + styleClass ) +} +hasClass( styleClass ) { +return super.hasClass( CMSQuery.classPrefix + styleClass ) +} +orAutoheight() { +return autoheight.apply(this,arguments); +}; +orButton() { +return button.apply(this,arguments); +}; +orLinkify() { +return linkify.apply(this,arguments); +}; +orSearch() { +return search.apply(this,arguments); +}; +orTree() { +return tree.apply(this,arguments); +}; +toggleAttr() { +return toggleAttr.call(this); +}; +} +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/openrat/api.min.js b/modules/cms/ui/themes/default/script/openrat/api.min.js @@ -0,0 +1,66 @@ +import $ from '../jquery-global.min.js'; +import Workbench from "./workbench.min.js"; +import Notice from "./notice.min.js"; +import Callback from "./callback.min.js"; +export default class Api { +static modes = { +get : 1, +write : 2, +}; +constructor() { +this.notifyBrowser = false; +this.mode = Api.modes.get; +} +sendData = function( formData ) { +console.debug( "API form data", formData ); +let api = this; +return new Promise( (resolve, reject) => { +let load = fetch( './api/', { 'method':'POST', body:formData } ); +load.then( response => { +if ( ! response.ok ) +reject( "Failed to post" ); +return response.json(); +}).then( data => { +for( let value of data['notices'] ) { +let notice = new Notice(); +notice.setContext( value.type, value.id, value.name ); +notice.log = value.log; +notice.setStatus( value.status ); +notice.msg = value.text; +notice.show(); +if ( api.notifyBrowser ) +notice.notifyBrowser() +}; +if ( data.success ) { +resolve(); +} +else { +for( name of data['errors'] ) +this.validationErrorForField( name ); +reject('API request failed'); +} +} ).catch( cause => { +console.warn( { +message: 'API request failed', +cause : cause, +data : formData, +} ); +let msg = ''; +try { +msg = JSON.parse( cause ).message; +} +catch( e ) { +msg = cause; +} +let notice = new Notice(); +notice.setStatus('error'); +notice.msg = msg; +notice.log = cause; +notice.show(); +reject( msg ); +} ); +} ); +} +validationErrorForField = function( nameOfField ) { +} +} +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/openrat/callback.min.js b/modules/cms/ui/themes/default/script/openrat/callback.min.js @@ -0,0 +1,16 @@ +export default class Callback { +constructor() { +this.list = []; +} +add( callable ) { +this.list.push( callable ); +} +fire() { +for( let c of this.list) +c.apply(null,arguments); +} +} +Callback.afterViewLoadedHandler = new Callback(); +Callback.dataChangedHandler = new Callback(); +Callback.afterNewActionHandler = new Callback(); +Callback.afterAllViewsLoaded = new Callback(); +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/openrat/components.js b/modules/cms/ui/themes/default/script/openrat/components.js @@ -6,11 +6,17 @@ import table from '../../../../../../template_engine/components/html/component_ import upload from '../../../../../../template_engine/components/html/component_upload/upload.js'; import Callback from "./callback.js"; -console.debug('registering component scripts'); +export default class Components { + + registerComponents() { + console.debug('registering component scripts'); + + Callback.afterViewLoadedHandler.add(editor); + Callback.afterViewLoadedHandler.add(group); + Callback.afterViewLoadedHandler.add(link); + Callback.afterViewLoadedHandler.add(qrcode); + Callback.afterViewLoadedHandler.add(table); + Callback.afterViewLoadedHandler.add(upload); + } +} -Callback.afterViewLoadedHandler.add( editor ); -Callback.afterViewLoadedHandler.add( group ); -Callback.afterViewLoadedHandler.add( link ); -Callback.afterViewLoadedHandler.add( qrcode ); -Callback.afterViewLoadedHandler.add( table ); -Callback.afterViewLoadedHandler.add( upload ); diff --git a/modules/cms/ui/themes/default/script/openrat/components.min.js b/modules/cms/ui/themes/default/script/openrat/components.min.js @@ -0,0 +1,18 @@ +import editor from '../../../../../../template_engine/components/html/component_editor/editor.min.js'; +import group from '../../../../../../template_engine/components/html/component_group/group.min.js'; +import link from '../../../../../../template_engine/components/html/component_link/link.min.js'; +import qrcode from '../../../../../../template_engine/components/html/component_qrcode/qrcode.min.js'; +import table from '../../../../../../template_engine/components/html/component_table/table.min.js'; +import upload from '../../../../../../template_engine/components/html/component_upload/upload.min.js'; +import Callback from "./callback.min.js"; +export default class Components { +registerComponents() { +console.debug('registering component scripts'); +Callback.afterViewLoadedHandler.add(editor); +Callback.afterViewLoadedHandler.add(group); +Callback.afterViewLoadedHandler.add(link); +Callback.afterViewLoadedHandler.add(qrcode); +Callback.afterViewLoadedHandler.add(table); +Callback.afterViewLoadedHandler.add(upload); +} +} +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/openrat/dialog.min.js b/modules/cms/ui/themes/default/script/openrat/dialog.min.js @@ -0,0 +1,77 @@ +import $ from "../jquery-global.min.js"; +import View from './view.min.js'; +import Notice from "./notice.min.js"; +import Workbench from "./workbench.min.js"; +import WorkbenchNavigator from "./navigator.min.js"; +export default class Dialog { +constructor() { +this.view; +this.isDirty = false; +this.element = $('.or-dialog-content .or-view'); +} +start( name,action,method,id,params ) +{ +if (!action) +action = Workbench.state.action; +if (!id) +id = Workbench.state.id; +let dialog = this; +let view = new View( action,method,id,params ); +Notice.removeAllNotices(); +$('.or-dialog-content .or-view').html(''); +$('.or-dialog-content .or-act-dialog-name').html( name ); +this.show(); +view.onCloseHandler.add( function() { +dialog.back(); +} ); +view.onChangeHandler.add( function() { +console.debug("Changes detected"); +dialog.isDirty = true; +dialog.element.addClass('view--is-dirty'); +}); +view.onSaveHandler.add( function() { +dialog.isDirty = false; +dialog.element.removeClass('view--is-dirty'); +}); +this.view = view; +Workbench.getInstance().startSpinner(); +let viewPromise = this.view.start( this.element ); +viewPromise.then( +() => Workbench.getInstance().stopSpinner() +); +return viewPromise; +} +show() { +WorkbenchNavigator.navigateToNew( Workbench.state ); +$('.or-dialog').removeClass('dialog--is-closed').addClass('dialog--is-open'); +if ( this.isDirty ) { +this.element.addClass('view--is-dirty'); +} +} +back() { +console.debug("Back from dialog"); +history.back(); +} +hide() { +$('.or-dialog').removeClass('dialog--is-open').addClass('dialog--is-closed'); +} +close() { +let dialog = this; +if ( this.isDirty ) { +// return; +let notice = new Notice(); +notice.msg = Workbench.language.REOPEN_CLOSED_DIALOG; +notice.setStatus( 'warning' ); +notice.timeout = 120; +notice.onClick.add( function() { +Workbench.dialog = dialog; +dialog.show(); +notice.close(); +}); +notice.show(); +} +$('.or-dialog-content .or-view.or-view--is-dirty').removeClass('view--is-dirty'); +this.hide(); +//$(document).unbind('keyup',this.escapeKeyClosingHandler); +} +} +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/openrat/form.min.js b/modules/cms/ui/themes/default/script/openrat/form.min.js @@ -0,0 +1,150 @@ +import $ from '../jquery-global.min.js'; +import Workbench from "./workbench.min.js"; +import Notice from "./notice.min.js"; +import Callback from "./callback.min.js"; +import Api from "./api.min.js"; +export default class Form { +static modes = { +showBrowserNotice : 1, +keepOpen : 2, +closeAfterSubmit : 4, +closeAfterSuccess : 8, +}; +constructor() { +this.onChangeHandler = new Callback(); +this.onSaveHandler = new Callback(); +this.onCloseHandler = new Callback(); +this.async = false; +this.afterSuccess = ''; +this.element = null; +this.autosave = false; +this.mode = Form.modes.keepOpen; +this.formMethod = 'GET'; +this.forwardToMethod = null; +} +setLoadStatus( isLoading ) { +if ( isLoading ) +Workbench.getInstance().startSpinner(); +else +Workbench.getInstance().stopSpinner(); +} +initOnElement( element ) { +this.element = element; +this.formMethod = $(this.element).attr('method').toUpperCase(); +this.afterSuccess = $(this.element).data('afterSuccess'); +this.forwardToMethod = $(this.element).data('forwardTo'); +this.async = $(this.element).data('async'); +let form = this; +if ( $(this.element).data('autosave') ) { +this.autosave = true; +$(this.element).find('input[type="checkbox"]').click( function() { +form.submit(Form.modes.keepOpen); +}); +$(this.element).find('select').change( function() { +form.submit(Form.modes.keepOpen); +}); +} +$(element).find('.or-act-form-cancel').click( function() { +form.cancel(); +}); +$(element).find('.or-act-form-reset').click( function() { +form.rollback(); +}); +$(element).find('.or-act-form-apply').click( function() { +form.submit(Form.modes.keepOpen); +}); +$(element).find('.or-act-form-save').click( function() { +form.submit(); +}); +$(element).find('.or-input').change( function() { +form.onChangeHandler.fire(); +}); +$(element).submit( function( event ) { +if ($(this).data('target')=='view') +{ +form.submit(); +event.preventDefault(); +} +}); +} +cancel() { +Notice.removeAllNotices(); +this.onCloseHandler.fire(); +} +rollback() { +this.element.trigger('reset'); +} +forwardTo(action, subaction, id, data) { +} +submit( mode ) { +if ( mode === undefined ) +if ( this.async ) +mode = Form.modes.closeAfterSubmit; +else +mode = Form.modes.closeAfterSuccess; +Notice.removeAllNotices(); +let status = new Notice(); +status.setStatus('info'); +status.inProgress(); +status.msg = Workbench.language.PROGRESS; +status.show(); +$(this.element).find('.or-input--error').removeClass('input--error'); +let formData = new FormData( $(this.element).get(0) ); +if (!formData.has('id') ) +formData.append('id',Workbench.state.id); +if (!formData.has('action') ) +formData.append('action',Workbench.state.action); +if ( this.formMethod == 'GET' ) +{ +this.forwardTo( formData.get('action'), formData.get('subaction'),formData.get('id,'),formData ); +$(status).remove(); +} +else +{ +if ( mode == Form.modes.closeAfterSubmit ) +this.onCloseHandler.fire(); +formData.append('output','json'); +this.sendFormData( formData ); +status.close(); +} +} +sendFormData = function( formData ) { +this.setLoadStatus(true); +let form = this; +let api = new Api(); +api.notifyBrowser = form.async; +api.validationErrorForField = (name) => { +$('.or-input[name='+name+']').addClass('input--error').parent().addClass('input--error').parents('.or-group').removeClass('closed').addClass('show').addClass('open'); +} +let result = api.sendData( formData ); +let mode = 0; +result.then( +() => { +form.onSaveHandler.fire(); +if (this.afterSuccess == 'forward') +mode = Form.modes.keepOpen; +if (mode == Form.modes.closeAfterSuccess) { +form.onCloseHandler.fire(); +$(form.element).closest('div.panel').find('div.header ul.views li.action.active').removeClass('dirty'); +} +if (form.afterSuccess) { +if (form.afterSuccess == 'reloadAll') { +Workbench.getInstance().reloadAll(); +} else if (form.afterSuccess == 'forward') { +if (form.forwardToMethod) +form.forwardTo(formData.get('action'), form.forwardToMethod, formData.get('id'), []); +} +} else { +if (async) +; +else +Workbench.getInstance().reloadViews(); +} +Callback.dataChangedHandler.fire(); +} +).catch( (reason) => { +}).finally( () => { +form.setLoadStatus(false); +}) +} +} +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/openrat/init.min.js b/modules/cms/ui/themes/default/script/openrat/init.min.js @@ -0,0 +1,2 @@ +import Workbench from "./workbench.min.js"; +Workbench.getInstance().initialize(); +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/openrat/navigator.js b/modules/cms/ui/themes/default/script/openrat/navigator.js @@ -16,7 +16,9 @@ export default class WorkbenchNavigator { } /** - * Setzt den State für den aktuellen History-Eintrag. + * Sets the state for the current history entry. + * This will be called once while initializing the workbench. + * * @param obj */ static toActualHistory(obj) { diff --git a/modules/cms/ui/themes/default/script/openrat/navigator.min.js b/modules/cms/ui/themes/default/script/openrat/navigator.min.js @@ -0,0 +1,12 @@ +export default class WorkbenchNavigator { +'use strict'; +static navigateToNew(obj) { +window.history.pushState(obj,obj.name,WorkbenchNavigator.createShortUrl(obj.action,obj.id) ); +} +static toActualHistory(obj) { +window.history.replaceState(obj,obj.name,WorkbenchNavigator.createShortUrl(obj.action,obj.id) ); +} +static createShortUrl(action,id) { +return './#/'+action+(id?'/'+id:''); +} +} +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/openrat/notice.min.js b/modules/cms/ui/themes/default/script/openrat/notice.min.js @@ -0,0 +1,126 @@ +import $ from '../jquery-global.min.js'; +import Workbench from './workbench.min.js'; +import Callback from "./callback.min.js"; +import WorkbenchNavigator from "./navigator.min.js"; +export default class Notice { +'use strict'; +static type = Object.freeze({ +warning: 0, +validation: 1, +info: 2, +success: 3, +error: 3, +loading: 3, +inactive: 4 +}); +constructor() { +this.typ = ''; +this.id = 0; +this.name = ''; +this.status = 'inactive'; +this.msg = ''; +this.log = ''; +this.timeout = 0; +this.element = $.create('div') +.addClass('notice' ) +.addClass('notice--is-inactive' ) +.addClass('collapsible' ) +.addClass('collapsible--is-closed'); +this.onClick = new Callback(); +} +before() { +}; +close() { +this.element.remove(); +} +setStatus( status ) { +this.element.removeClass('notice--' + this.status ); +this.status = status; +this.element.addClass('notice--' + this.status ); +} +inProgress() { +} +stopProgress() { +} +show() { +console.debug('user notice: ' + this.msg); +let notice = this; +this.element.removeClass('notice--is-inactive'); +this.element.appendTo( $('.or-notice-container') ); +let toolbar = $.create('div').addClass("notice-toolbar"); +toolbar.appendTo(this.element); +toolbar.append( $.create('i').addClass('image-icon').addClass('image-icon--menu-close').addClass('act-notice-close') ); +this.element.append( $.create('i').addClass('image-icon').addClass('image-icon--node-open' ).addClass('collapsible--on-open' ) ); +this.element.append( $.create('i').addClass('image-icon').addClass('image-icon--node-closed').addClass('collapsible--on-closed') ); +this.element.append( $.create('span').addClass('notice-text').addClass('collapsible-act-switch').text( Notice.htmlEntities(this.msg) ) ); +if (this.name) { +this.element.append( $.create('div').addClass('notice-name').addClass('collapsible-value').append( $.create('a').addClass('act-clickable').attr('href',WorkbenchNavigator.createShortUrl(this.typ, this.id)).data('type',open).data('action',this.typ).data('id',this.id).append( $.create('i').addClass('notice-action-full').addClass('image-icon').addClass('image-icon--action-' + this.typ )).append( $.create('span').text(this.name ))).orLinkify() ); +} +if (this.log) +this.element.append( $.create('div').addClass('notice-log').addClass('collapsible-value').append( $.create('pre').text(Notice.htmlEntities(this.log)))); +this.element.append( $.create('div').addClass('notice-date').addClass('collapsible-value').text(new Date().toLocaleTimeString())); +this.element.find('.or-notice-text').click( function () { +notice.onClick.fire(); +} ); +Workbench.registerOpenClose( this.element ); +this.element.find('.or-act-notice-close').click(function () { +notice.close(); +}); +if ( !this.timeout ) { +switch( this.status ) { +case 'ok' : this.timeout = 3; break; +case 'info' : this.timeout = 30; break; +case 'warning': this.timeout = 40; break; +case 'error' : this.timeout = 50; break; +default: this.timeout = 10; console.error('unknown notice status: '+this.status); +} +} +if (this.timeout) { +let timer = setTimeout(function () { +notice.close(); +}, this.timeout * 1000); +this.element.click( function () { +window.clearTimeout( timer ); +} ); +} +} +setContext(type,id,name) { +this.typ = type; +this.id = id; +this.name = name; +} +start(type, id, name, status, msg, log = null, notifyTheBrowser = false) { +this.setContext(type,id,name); +this.msg = msg; +this.log = log; +if (notifyTheBrowser) +this.notifyBrowser(msg); +this.setStatus(status); +} +notifyBrowser() +{ +let text = this.msg; +if (!("Notification" in window)) { +return; +} +else if (Notification.permission === "granted") { +let notification = new Notification(text); +} +else if (Notification.permission !== 'denied') { +Notification.requestPermission(function (permission) { +if (permission === "granted") { +let notification = new Notification(text); +} +}); +} +} +static htmlEntities( str ) { +return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'); +} +static removeNoticesWithStatus( status) { +$('.or-notice-container').find('.or-notice--'+status).remove(); +} +static removeAllNotices( status) { +$('.or-notice-container').find('.or-notice').remove(); +} +} +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/openrat/view.js b/modules/cms/ui/themes/default/script/openrat/view.js @@ -104,8 +104,6 @@ export default class View { form.initOnElement(this); }); - let components = await import( './components.js'); - view.fireViewLoadedEvents( element ); } catch( cause ) { diff --git a/modules/cms/ui/themes/default/script/openrat/view.min.js b/modules/cms/ui/themes/default/script/openrat/view.min.js @@ -0,0 +1,99 @@ +import $ from '../jquery-global.min.js'; +import Callback from "./callback.min.js"; +import Form from "./form.min.js"; +import Notice from "./notice.min.js"; +export default class View { +constructor( action,method,id,params ) { +this.action = action; +this.method = method; +this.id = id; +this.params = params; +this.onCloseHandler = new Callback(); +this.onChangeHandler = new Callback(); +this.onSaveHandler = new Callback(); +} +before() { +}; +start( element ) { +this.before(); +this.element = element; +return this.loadView(); +} +afterLoad() { +} +close() { +this.onCloseHandler.fire(); +} +fireViewLoadedEvents(element) { +Callback.afterViewLoadedHandler.fire( element ); +} +async loadView() { +let url = View.createUrl( this.action,this.method,this.id,this.params,false); +let element = this.element; +let view = this; +console.debug( view ); +try { +let response = await fetch( url,{} ); +if ( ! response.ok ) +throw "failed to load the view"; +let data = await response.text(); +if ( ! data ) +data = ''; +$(element).html(data); +$(element).find('form').each( function() { +let form = new Form(); +form.onChangeHandler.add( () => { view.onChangeHandler.fire() } ); +form.onSaveHandler .add( () => { view.onSaveHandler .fire() } ); +form.onCloseHandler .add( () => { view.close() } ); +form.forwardTo = function (action, subaction, id, data) { +view.action = action; +view.method = subaction; +view.id = id; +view.params = data; +view.loadView(); +} +form.initOnElement(this); +}); +view.fireViewLoadedEvents( element ); +} +catch( cause ) { +$(element).html(""); +console.error( {view:view, url:url, cause: cause} ); +let notice = new Notice(); +notice.setStatus('error'); +notice.msg = "View error"; +notice.log = cause; +notice.show(); +} +finally { +} +} +static createUrl(action,subaction,id,extraid={},api=false ) +{ +let url = './'; +if ( api ) +url += 'api/'; +url += '?'; +if(action) +url += '&action='+action; +if(subaction) +url += '&subaction='+subaction; +if(id) +url += '&id='+id; +if ( extraid instanceof FormData ) { +for (let pair of extraid.entries()) { +url += '&' + pair[0] + '=' + pair[1]; +} +} +else if ( extraid instanceof Object ) { +Object.keys(extraid).forEach( (key) => { +url += '&' + key + '=' + extraid[key]; +}); +} +else +throw "Illegal argument"; +if ( api ) +url += '&output=json'; +return url; +} +} +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/openrat/workbench.js b/modules/cms/ui/themes/default/script/openrat/workbench.js @@ -4,6 +4,7 @@ import View from './view.js'; import Callback from './callback.js'; import WorkbenchNavigator from "./navigator.js"; import Notice from "./notice.js"; +import Components from "./components.js"; export default class Workbench { @@ -49,6 +50,7 @@ export default class Workbench { initialize() { this.checkBrowserRequirements(); + this.initializeState(); $('html').removeClass('nojs'); @@ -65,7 +67,7 @@ export default class Workbench { this.loadNewActionState(ev.state); }; - this.initializeState(); + this.registerWorkbench(); this.initializeStartupNotices(); this.initializeEvents(); this.initializeKeystrokes(); @@ -108,6 +110,16 @@ export default class Workbench { } + /** + * Register this workbench in the window object + * Only for debugging in browser console. + */ + registerWorkbench() { + + window.OpenRat = { workbench: this }; + } + + /** * Sets the workbench state with action/id. * @@ -632,6 +644,8 @@ export default class Workbench { */ initializeEvents() { + new Components().registerComponents(); + // Mit der Maus irgendwo hin geklickt, das Menü muss schließen. $('body').click( () => { this.closeMenu(); diff --git a/modules/cms/ui/themes/default/script/openrat/workbench.min.js b/modules/cms/ui/themes/default/script/openrat/workbench.min.js @@ -0,0 +1,573 @@ +import $ from '../jquery-global.min.js'; +import Dialog from './dialog.min.js'; +import View from './view.min.js'; +import Callback from './callback.min.js'; +import WorkbenchNavigator from "./navigator.min.js"; +import Notice from "./notice.min.js"; +import Components from "./components.min.js"; +export default class Workbench { +'use strict'; +static state = { +action: '', +id: 0, +extra: {} +}; +static dialog; +static instance; +constructor() { +this.popupWindow = null; +Callback.dataChangedHandler.add( () => { +if ( Workbench.popupWindow ) +Workbench.popupWindow.location.reload(); +} ); +} +static getInstance() { +if ( ! Workbench.instance ) +Workbench.instance = new Workbench(); +return Workbench.instance; +} +initialize() { +this.checkBrowserRequirements(); +this.initializeState(); +$('html').removeClass('nojs'); +$('.or--initial-hidden').removeClass('-initial-hidden'); +window.onpopstate = ev => { +console.debug("Event after navigating",ev); +this.closeDialog(); +this.closeMenu(); +this.loadNewActionState(ev.state); +}; +this.registerWorkbench(); +this.initializeStartupNotices(); +this.initializeEvents(); +this.initializeKeystrokes(); +this.reloadAll().then( () => { +Callback.afterNewActionHandler.fire(); +} +); +this.initializePingTimer(); +this.initializeDirtyWarning(); +console.info('Application started'); +} +initializeDirtyWarning() { +window.addEventListener('beforeunload', function (e) { +if ( $('.or-view--is-dirty').length > 0 ) { +e.preventDefault(); +return 'Unsaved content will be lost.'; +} +else { +return undefined; +} +}); +} +registerWorkbench() { +window.OpenRat = { workbench: this }; +} +initializeState() { +let parts = window.location.hash.split('/'); +let state = { action:'index',id:0 }; +if ( parts.length >= 2 ) +state.action = parts[1].toLowerCase(); +if ( parts.length >= 3 ) +state.id = parts[2].replace(/[^0-9_]/gim,""); +Workbench.state = state; +WorkbenchNavigator.toActualHistory( state ); +} +checkBrowserRequirements() { +if ( ! window.Promise ) { +console.error('This browser does not support Promises, which is required for this application.' ); +let notice = new Notice(); +notice.msg = 'This browser is not supported'; +notice.msg = 'Promises are not available'; +notice.show(); +} +if ( ! window.fetch ) { +console.error('This browser does not support the fetch API, which is required for this application.' ); +let notice = new Notice(); +notice.setStatus('error'); +notice.msg = 'This browser is not supported'; +notice.log = 'Fetch API is not available'; +notice.show(); +} +} +initializePingTimer() { +let ping = async () => { +let url = View.createUrl('profile','ping',0, {}, true); +console.debug('ping'); +try { +let response = await fetch( url ); +if ( !response.ok ) +throw "ping failed"; +} catch( cause ) { +console.warn( {message: 'The server ping has failed.',cause:cause }); +if ($('.or-view--is-dirty').length > 0) { +window.alert("The server session is lost, please save your data."); +} +else { +} +} +} +let timeoutMinutes = 5; +window.setInterval( ping, timeoutMinutes*60*1000 ); +} +loadNewActionState(state) { +console.debug("New state",state); +Workbench.state = state; +this.reloadViews(); +this.filterMenus(); +Callback.afterNewActionHandler.fire(); +} +closeDialog() { +if ( Workbench.dialog ) { +Workbench.dialog.close(); +Workbench.dialog = null; +} +} +createDialog() { +this.closeDialog(); +Workbench.dialog = new Dialog(); +return Workbench.dialog; +} +reloadViews() { +this.startSpinner(); +let promise = this.loadViews( $('.or-workbench .or-act-view-loader') ); +promise.then( +() => this.stopSpinner() +); +return promise; +} +startSpinner() { +$('.or-workbench-loader').addClass('loader').addClass('loader--is-active'); +} +stopSpinner() { +$('.or-workbench-loader').removeClass('loader').removeClass('loader--is-active'); +} +reloadAll() { +this.startSpinner(); +let promise = this.loadViews( $('.or-act-view-loader,.or-act-view-static') ); +console.debug('reloading all views'); +let stylePromise = this.loadUserStyle(); +let languagePromise = this.loadLanguage(); +let settingsPromise = this.loadUISettings(); +let all = Promise.all( [ promise,stylePromise,languagePromise,settingsPromise ] ); +all.then( +() => this.stopSpinner() +); +return all; +} +async loadUserStyle() { +let url = View.createUrl('profile', 'userinfo', 0, {}, true); +let response = await fetch(url); +let json = await response.json(); +let style = json.output['style']; +this.setUserStyle(style); +let color = json.output['theme-color']; +this.setThemeColor(color); +} +static settings = {}; +static language = {}; +async loadLanguage() { +let url = View.createUrl('profile', 'language', 0, {}, true); +let response = await fetch(url); +let data = await response.json(); +Workbench.language = data.output.language; +} +async loadUISettings() { +let url = View.createUrl('profile', 'uisettings', 0, {}, true); +let response = await fetch(url); +let data = await response.json(); +Workbench.settings = data.output.settings.settings; +} +loadViews( $views ) +{ +let wb = this; +let promises = []; +$views.each(function (idx) { +let $targetDOMElement = $(this); +promises.push( wb.loadNewActionIntoElement( $targetDOMElement ) ); +}); +let all = Promise.all( promises ); +return all; +} +loadNewActionIntoElement( $viewElement ) +{ +let action; +if ( $viewElement.is('.or-act-view-static') ) +action = $viewElement.attr('data-action'); +else +action = Workbench.state.action; +let id = Workbench.state.id; +let params = Workbench.state.extra; +let method = $viewElement.data('method'); +let view = new View( action,method,id,params ); +return view.start( $viewElement ); +} +setUserStyle( styleName ) +{ +let styleUrl = View.createUrl('index','themestyle',0,{'style':styleName} ); +document.getElementById('user-style').setAttribute('href',styleUrl); +} +setThemeColor( color ) +{ +document.getElementById('theme-color').setAttribute('content',color); +} +static setApplicationTitle( newTitle ) { +let title = document.querySelector('head > title'); +let defaultTitle = title.dataset.default; +title.textContent = (newTitle ? newTitle + ' - ' : '') + defaultTitle; +} +static registerOpenClose = function( $el ) +{ +$($el).children('.or-collapsible-act-switch').click( function() { +let $group = $(this).closest('.or-collapsible'); +if ( $group.hasClass('collapsible--is-visible') ) { +$group.removeClass('collapsible--is-visible'); +setTimeout( () => { +$group.removeClass('collapsible--is-open'); +},300 ); +} +else { +$group.addClass('collapsible--is-open'); +$group.addClass('collapsible--is-visible'); +} +}); +} +openNewAction( name,action,id ) +{ +$('.or-workbench-navigation').removeClass('workbench-navigation--is-open'); +Workbench.setApplicationTitle( name ); +let newState = {'action':action, 'id':id }; +this.loadNewActionState( newState ); +WorkbenchNavigator.navigateToNew( newState ); +} +registerDraggable(viewEl) { +$(viewEl).find('.or-draggable').attr('draggable','true') +.on('dragstart',(e)=>{ +$('.or-workbench').addClass('workbench--drag-active'); +let link = e.currentTarget; +e.dataTransfer.effectAllowed = 'link'; +e.dataTransfer.setData('id' , link.dataset.id ); +e.dataTransfer.setData('action', link.dataset.action); +console.debug('drag started',link,e.dataTransfer); +}) +.on('drag',(e)=>{ +}) +.on('dragend',(e)=>{ +$('.or-workbench').removeClass('workbench--drag-active'); +}); +} +registerDroppable(viewEl) { +$(viewEl).find('.or-droppable-selector').on('dragover', (e) => { +e.preventDefault(); +}).on('drop', (event) => { +let data = event.dataTransfer.getData('text'); +console.debug('dropped:', dropped); +let id = $(data).find('.or-link').data('id'); +let name = $(data).find('.or-navtree-text').text(); +if (!name) +name = id; +$(this).find('.or-selector-link-value').val(id); +$(this).find('.or-selector-link-name').val(name).attr('placeholder', name); +}); +$(viewEl).find('.or-droppable') +} +registerAsDroppable( el, onDrop ) { +el.addEventListener('dragover', (e) => { +e.preventDefault(); +}); +el.addEventListener('dragenter', (e) => { +e.stopPropagation(); +e.preventDefault(); +e.currentTarget.classList.add('or-workbench--drop-active'); +}); +el.addEventListener('dragleave', (e) => { +e.stopPropagation(); +e.preventDefault(); +e.currentTarget.classList.remove('or-workbench--drop-active'); +}); +el.addEventListener('drop', onDrop); +} +static htmlDecode(input) { +let doc = new DOMParser().parseFromString(input, "text/html"); +return doc.documentElement.textContent; +} +async filterMenus() { +let action = Workbench.state.action; +let id = Workbench.state.id; +$('.or-workbench-title .or-dropdown-entry.or-act-clickable').addClass('dropdown-entry--active'); +$('.or-workbench-title .or-filtered').removeClass('dropdown-entry--active').addClass('dropdown-entry--inactive'); +$('.or-workbench-title .or-filtered .or-link').attr('data-id', id); +let url = View.createUrl('profile', 'available', id, {'queryaction': action}, true); +let response = await fetch(url); +let data = await response.json(); +for (let method of Object.values(data.output.views)) +$('.or-workbench-title .or-filtered > .or-link[data-method=\'' + method + '\']') +.parent() +.addClass('dropdown-entry--active') +.removeClass('dropdown-entry--inactive'); +} +initializeStartupNotices() { +$('.or-act-initial-notice').each( function() { +let notice = new Notice(); +notice.setStatus('info'); +notice.msg = $(this).text(); +notice.show(); +}); +} +initializeKeystrokes() { +let keyPressedHandler = (event) => { +if (event.key === 'F4') { +let dialog = this.createDialog(); +dialog.start('', '', 'prop', 0, {}); +} +if (event.key === 'F2') { +if ($('.or-workbench').hasClass('workbench--navigation-is-small')) +$('.or-act-nav-wide').click(); +else +$('.or-act-nav-small').click(); +} +if (event.code === 'Escape') { +this.closeDialog(); +} +}; +document.addEventListener('keydown',keyPressedHandler); +} +closeMenu() { +$('.or-menu').removeClass('menu--is-open'); +} +initializeEvents() { +new Components().registerComponents(); +$('body').click( () => { +this.closeMenu(); +}); +$('.or-dialog-filler,.or-act-dialog-close').click( (e) => +{ +e.preventDefault(); +this.closeDialog(); +} +); +$('.or-act-navigation-close').click( () => { +$('.or-workbench-navigation').removeClass('workbench-navigation--is-open'); +$('.or-workbench').removeClass('workbench--navigation-is-open'); +}); +$('.or-workbench-title .or-act-nav-small').click( () => { +$('.or-workbench').addClass('workbench--navigation-is-small'); +$('.or-workbench-navigation').addClass('workbench-navigation--is-small'); +}); +$('.or-search-input .or-input').orSearch( { +onSearchActive: function() { +$('.or-search').addClass('search--is-active'); +}, +onSearchInactive: function() { +$('.or-search').removeClass('search--is-active'); +}, +dropdown : '.or-act-search-result', +resultEntryClass: 'search-result-entry', +//openDropdown: true, +select : function(obj) { +Workbench.getInstance().openNewAction( obj.name, obj.action, obj.id ); +}, +afterSelect: function() { +} +} ); +$('.or-search .or-act-search-delete').click( () => { +$('.or-search .or-title-input').val('').input(); +} ); +Callback.afterNewActionHandler.add( function() { +$('.or-sidebar').find('.or-sidebar-button').orLinkify(); +} +); +Callback.afterNewActionHandler.add( function() { +let url = View.createUrl('tree','path',Workbench.state.id, {'type':Workbench.state.action} ); +let loadPromise = fetch( url ); +function openNavTree(action, id) { +let $navControl = $('.or-link[data-action="'+action+'"][data-id="'+id+'"]').closest('.or-navtree-node'); +if ( $navControl.is( '.or-navtree-node--is-closed' ) ) +$navControl.find('.or-navtree-node-control').click(); +} +loadPromise +.then( response => response.text() ) +.then( data => { +$('.or-breadcrumb').empty().html( data ).find('.or-act-clickable').orLinkify(); +$('.or-breadcrumb a').each( function () { +let action = $(this).data('action'); +let id = $(this).data('id' ); +openNavTree( action, id ); +}); +$('.or-link--is-active').removeClass('link--is-active'); +let action = Workbench.state.action; +let id = Workbench.state.id; +if (!id) id = '0'; +$('.or-link[data-action=\''+action+'\'][data-id=\''+id+'\']').addClass('link--is-active'); +openNavTree( action,id ); +}).catch( cause => { +console.warn( { +message : 'Failed to load path', +url : url, +cause : cause } ); +}).finally(function () { +}); +} ); +Callback.afterViewLoadedHandler.add( function(element) { +$(element).find('.or-button').orButton(); +} ); +Callback.afterViewLoadedHandler.add( function(element) { +if ( Workbench.popupWindow ) +$(element).find("a[data-type='popup']").each( function() { +Workbench.popupWindow.location.href = $(this).attr('data-url'); +}); +}); +Callback.afterViewLoadedHandler.add( function(element) { +$(element).find(".or-input--password").dblclick( function() { +$(this).toggleAttr('type','text','password'); +}); +$(element).find(".or-act-make-visible").click( function() { +$(this).toggleClass('btn--is-active' ); +$(this).parent().children('input').toggleAttr('type','text','password'); +}); +}); +Callback.afterViewLoadedHandler.add( function($element) { +$element.find('.or-act-load-nav-tree').each( async function() { +let type = $(this).data('type') || 'root'; +let loadBranchUrl = View.createUrl('tree','branch',0,{type:type}); +let $targetElement = $(this); +let response = await fetch( loadBranchUrl ); +let html = await response.text(); +let $ul = $.create('ul' ).addClass('navtree-list'); +$ul.appendTo( $targetElement.empty() ).html( html ); +$ul.find('li').orTree( { +'openAction': function( name,action,id) { +Workbench.getInstance().openNewAction( name,action,id ); +} +} ); +$ul.find('.or-act-clickable').orLinkify(); +$ul.find('.or-navtree-node-control').first().click(); +} ); +} ); +Callback.afterViewLoadedHandler.add( function(viewEl ) { +$(viewEl).find('.or-act-nav-open-close').click( function() { +$('.or-workbench').toggleClass('workbench--navigation-is-open'); +$('.or-workbench-navigation').toggleClass('workbench-navigation--is-open'); +}); +$(viewEl).find('.or-act-nav-small').click( function() { +$('.or-workbench').addClass('workbench--navigation-is-small'); +$('.or-workbench-navigation').addClass('workbench-navigation--is-small'); +}); +$(viewEl).find('.or-act-nav-wide').click( function() { +$('.or-workbench').removeClass('workbench--navigation-is-small'); +$('.or-workbench-navigation').removeClass('workbench-navigation--is-small'); +}); +$(viewEl).find('.or-act-selector-tree-button').click( function() { +let $selector = $(this).parent('.or-selector'); +let $targetElement = $selector.find('.or-act-load-selector-tree'); +if ( $selector.hasClass('selector--is-tree-active') ) { +$selector.removeClass('selector--is-tree-active'); +$targetElement.empty(); +} +else { +$selector.addClass('selector--is-tree-active'); +var selectorEl = this; +let id = $(this).data('init-folder-id'); +let type = id?'folder':'projects'; +let loadBranchUrl = './?action=tree&subaction=branch&id='+id+'&type='+type; +let load = fetch( loadBranchUrl ); +load +.then( response => response.text() ) +.then( html => { +let $ul = $.create('ul' ).addClass('navtree-list'); +$ul.appendTo( $targetElement ).append( html ); +$ul.find('li').orTree( +{ +'openAction' : function(name,action,id) { +$selector.find('.or-selector-link-value').val(id ); +$selector.find('.or-selector-link-name' ).val('').attr('placeholder',name); +$selector.removeClass('selector--is-tree-active'); +$targetElement.empty(); +} +} +); +$ul.find('.or-act-clickable').orLinkify(); +$ul.find('.or-navtree-node-control').first().click(); +} ); +} +} ); +registerDragAndDrop(viewEl); +$(viewEl).find('.or-theme-chooser').change( function() { +Workbench.getInstance().setUserStyle( this.value ); +}); +function registerMenuEvents($element ) +{ +$($element).find('.or-menu-category').click( function(event) { +event.stopPropagation(); +$(this).closest('.or-menu').toggleClass('menu--is-open'); +}); +$($element).find('.or-menu-category').mouseover( function() { +$(this).closest('.or-menu').find('.or-menu-category').removeClass('menu-category--is-open'); +$(this).addClass('menu-category--is-open'); +}); +} +function registerSelectorSearch( $element ) +{ +$($element).find('.or-act-selector-search').orSearch( { +onSearchActive: function() { +$(this).parent('or-selector').addClass('selector-search--is-active'); +}, +onSearchInactive: function() { +$(this).parent('or-selector').removeClass('selector-search--is-active' ); +}, +dropdown: '.or-act-selector-search-results', +resultEntryClass: 'or-search-result-entry', +select: function(obj) { +$($element).find('.or-selector-link-value').val(obj.id ); +$($element).find('.or-selector-link-name' ).val(obj.name).attr('placeholder',obj.name); +}, +afterSelect: function() { +$('.or-dropdown.or-act-selector-search-results').empty(); +} +} ); +} +function registerTree(element) { +} +registerMenuEvents ( viewEl ); +registerSelectorSearch( viewEl ); +registerTree ( viewEl ); +function registerDragAndDrop(viewEl) +{ +Workbench.getInstance().registerDraggable(viewEl); +Workbench.getInstance().registerDroppable(viewEl); +} +registerDragAndDrop(viewEl); +} ); +}; +static async addStyle( id, href ) { +return new Promise( (resolve,reject) => { +let styleEl = document.getElementById(id); +if (!styleEl) { +styleEl = document.createElement('link'); +styleEl.addEventListener('load',resolve); +styleEl.setAttribute('rel', 'stylesheet'); +styleEl.setAttribute('type', 'text/css'); +styleEl.setAttribute('href', href); +styleEl.setAttribute('id', id); +document.getElementsByTagName('head')[0].appendChild(styleEl); +} else { +resolve(); +} +} ); +} +static async addScript( id, href ) { +return new Promise( (resolve,reject) => { +let scriptEl = document.getElementById( id ); +if ( ! scriptEl ) { +scriptEl = document.createElement( 'script' ); +scriptEl.setAttribute('id' ,id ); +scriptEl.setAttribute('type','text/javascript' ); +scriptEl.addEventListener('load',resolve); +scriptEl.setAttribute('src',href ); +document.getElementsByTagName('head')[0].appendChild(scriptEl); +} else { +resolve(); +} +} ); +} +} +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/plugin/jquery-plugin-orAutoheight.min.js b/modules/cms/ui/themes/default/script/plugin/jquery-plugin-orAutoheight.min.js @@ -0,0 +1,16 @@ +import $ from "../jquery-global.min.js"; +export default function() { +let resize = function( element ) +{ +let lines = $(element).val().split("\n").length; +$(element).attr('rows',lines+3); +}; +$(this).each(function(i) +{ +resize(this); +}); +return $(this).keypress(function() +{ +resize(this); +}); +}; +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/plugin/jquery-plugin-orButton.min.js b/modules/cms/ui/themes/default/script/plugin/jquery-plugin-orButton.min.js @@ -0,0 +1,15 @@ +import $ from "../jquery-global.min.js"; +export default function( options ) +{ +let settings = $.extend( { +'selectorForClose': '.or-view' +}, options); +let button = this; +$( settings.selectorForClose ).click( function() { +}); +return $(this) +.addClass('button--is-watched') +.click( function() { +$(this).toggleClass('button--is-active'); +} ) ; +}; +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/plugin/jquery-plugin-orLinkify.min.js b/modules/cms/ui/themes/default/script/plugin/jquery-plugin-orLinkify.min.js @@ -0,0 +1,80 @@ +import $ from "../jquery-global.min.js"; +import Workbench from "../openrat/workbench.min.js"; +import Api from "../openrat/api.min.js"; +export default function( options ) +{ +var settings = $.extend( { +'openAction' : function(name,action,id) { +Workbench.getInstance().openNewAction( name,action,id ); +} +}, options); +$(this).addClass('linkified'); +if ( $(this).is('a') ) +$(this).addClass('act-prevented-link').click( function(event) { +event.preventDefault(); +} ); +else +$(this).find('a').addClass('act-prevented-sublink').click( function(event) { +event.preventDefault(); +} ); +return $(this).click(function(event) +{ +let $el = $(this); +let $link; +if ( $el.is('a') ) +$link = $el; +else +$link = $el.find('a').first(); +let type = $link.attr('data-type'); +if ( $link.parent().hasClass('dropdown-entry--inactive') ) +return; +switch( type ) +{ +case 'post': +let api = new Api(); +api.mode = Api.modes.write; +let formData = new FormData(); +let params = JSON.parse( $link.attr('data-data') ); +params.output = 'json'; +Object.keys( params ).forEach( (key) => { +formData.append( key, params[key] ); +} ); +if (!formData.get('id') ) +formData.set('id',Workbench.state.id); +if (!formData.get('action') ) +formData.set('action',Workbench.state.action); +api.sendData( formData ); +break; +case 'edit': +case 'dialog': +let dialog = Workbench.getInstance().createDialog(); +let name = $link.attr('data-name'); +if ( !name ) +name = $link.text(); +let extraValue = Workbench.htmlDecode($link.attr('data-extra')); +let extraData = JSON.parse(extraValue); +dialog.start(name,$link.attr('data-action'),$link.attr('data-method'),$link.attr('data-id'),extraData ); +break; +case 'external': +window.open( $link.attr('data-url'),' _blank' ); +break; +case 'window': +window.location.href = View.createUrl($link.attr('data-action'),$link.attr('data-method'),$link.attr('data-id')); +break; +case 'popup': +Workbench.popupWindow = window.open( $link.attr('data-url'), 'Popup', 'location=no,menubar=no,scrollbars=yes,toolbar=no,resizable=yes'); +break; +case 'help': +help($link,$link.attr('data-url'),$link.attr('data-suffix') ); +break; +case 'fullscreen': +fullscreen($link); +break; +case 'open': +settings.openAction( $link.text().trim(),$link.attr('data-action'),$link.attr('data-id') ); +break; +default: +throw "UI error: Unknown link type: "+type+" in link "+$link.html(); +} +}); +}; +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/plugin/jquery-plugin-orSearch.min.js b/modules/cms/ui/themes/default/script/plugin/jquery-plugin-orSearch.min.js @@ -0,0 +1,91 @@ +import $ from "../jquery-global.min.js"; +import WorkbenchNavigator from "../openrat/navigator.min.js"; +import Workbench from "../openrat/workbench.min.js"; +export default function( options ) +{ +let settings = $.extend( { +'dropdown': $(), +'select' : function( obj ) {}, +'afterSelect' : function() {}, +'onSearchActive' : function() {}, +'onSearchInactive' : function() {}, +'openDropdown' : true, +'action': 'search', +'method': 'quicksearch', +'resultEntryClass': 'dropdown-entry', +}, options); +let searchInput = $(this) +let dropdownEl = $( settings.dropdown ); +let closeSearch = function() { +settings.onSearchInactive(); +$(dropdownEl).empty(); +dropdownEl.removeClass('search-result--is-active'); +}; +$(this).on('keydown',async function(e) { +if ( e.keyCode == 13 ) { +let dialog = Workbench.getInstance().createDialog(); +closeSearch(); +dialog.start('','search','edit',0,{'text':searchInput.val()}); +searchInput.val(''); +} +} ); +return $(this).input(async function() +{ +let searchArgument = searchInput.val(); +if ( searchArgument.length ) +{ +settings.onSearchActive(); +$('.or-search').addClass('search--is-active'); +dropdownEl.addClass('search-result--is-active'); +let url = './api/?action='+settings.action+'&subaction='+settings.method+'&output=json&search='+searchArgument; +let response = await fetch( url, { +method: 'GET', +headers: { +'Content-Type': 'application/json', +} } ); +if ( ! response.ok ) +throw "Search request getting an error"; +let data = await response.json(); +$(dropdownEl).empty(); +for (let id in data.output.result) { +let result = data.output.result[id]; +let div = $.create('div') +.addClass( settings.resultEntryClass ) +.addClass( settings.resultEntryClass + '--active' ) +.attr('title',result.desc); +div.data( 'name' , result.name ); +div.data( 'action', result.type ); +div.data( 'id' , result.id ); +let link = $.create('a') +.addClass('link') +.attr('href', WorkbenchNavigator.createShortUrl(result.type, result.id)); +link.click(function (e) { +e.preventDefault(); +}); +$(link).append( +$.create('i').addClass('image-icon').addClass('image-icon--action-' + result.type) +); +$(link).append( +$.create('span').addClass('dropdown-text').text(result.name) +); +$(div ).append(link); +$(dropdownEl).append(div); +} +if (data.output.result && settings.openDropdown) { +$(dropdownEl).addClass('dropdown--is-open'); +} else { +$(dropdownEl).removeClass('dropdown--is-open'); +} +$(dropdownEl).find('.or-search-result-entry').click(function (e) { +settings.select( $(this).data() ); +settings.afterSelect(); +searchInput.val(''); +closeSearch(); +}); +} +else +{ +closeSearch(); +} +}); +}; +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/plugin/jquery-plugin-orTree.min.js b/modules/cms/ui/themes/default/script/plugin/jquery-plugin-orTree.min.js @@ -0,0 +1,65 @@ +import $ from "../jquery-global.min.js"; +import Workbench from "../openrat/workbench.min.js"; +import Notice from "../openrat/notice.min.js"; +export default function(options) +{ +let settings = $.extend( { +'openAction' : function(name,action,id) { +} +}, options); +let registerTreeBranchEvents = function (viewEl) +{ +Workbench.getInstance().registerDraggable(viewEl); +} +$(this).each(function (idxx, treeEl) +{ +$(treeEl).children('.or-navtree-node-control').click( function () +{ +let $node = $(this).parent('.or-navtree-node'); +if ($node.is('.or-navtree-node--is-open')) { +$node.children('ul').remove(); +$node.removeClass('navtree-node--is-open').addClass('navtree-node--is-closed').find('.or-navtree-tree-icon').removeClass('image-icon--node-open').addClass('image-icon--node-closed'); +} +else { +Workbench.getInstance().startSpinner(); +let $link = $node.find('a'); +let id = $link.data('id'); +let extraId = Workbench.htmlDecode($link.data('extra')); +let loadBranchUrl = './?action=tree&subaction=branch&id=' + id + ''; +if (typeof extraId === 'string') +extraId = JSON.parse(extraId); +if (typeof extraId === 'object') { +Object.keys(extraId).forEach( (name)=> { +loadBranchUrl = loadBranchUrl + '&' + name + '=' + extraId[name]; +}); +} +else { +; +} +console.debug( { url:loadBranchUrl } ); +fetch( loadBranchUrl ) +.then( response => { if (!response.ok) throw "Failed to load tree"; return response } ) +.then( response => response.text() ) +.then( html => { +let $ul = $.create('ul' ).addClass('navtree-list'); +$(treeEl).append($ul); +$ul.html( html ); +$ul.find('li').orTree(settings); +registerTreeBranchEvents($ul); +$ul.find('.or-act-clickable').orLinkify( { +'openAction':settings.openAction +} ); +//$ul.slideDown('fast'); +}).catch( cause => { +console.error( {message:'Failed to load subtree',url:loadBranchUrl,cause:cause}); +let notice = new Notice(); +notice.setStatus( 'error' ); +notice.msg = cause; +}).finally( () => { +Workbench.getInstance().stopSpinner(); +}); +$node.addClass('navtree-node--is-open').removeClass('navtree-node--is-closed').find('.or-navtree-tree-icon').addClass('image-icon--node-open').removeClass('image-icon--node-closed'); +} +}); +}); +}; +\ No newline at end of file diff --git a/modules/cms/ui/themes/default/script/plugin/jquery-plugin-toggleAttr.min.js b/modules/cms/ui/themes/default/script/plugin/jquery-plugin-toggleAttr.min.js @@ -0,0 +1,10 @@ +import $ from "../jquery-global.min.js"; +export default function(attr, attr1, attr2) { +return this.each(function() { +let self = $(this); +if (self.attr(attr) == attr1) +self.attr(attr, attr2); +else +self.attr(attr, attr1); +}); +}; +\ No newline at end of file diff --git a/modules/template_engine/components/html/component_editor/editor.js b/modules/template_engine/components/html/component_editor/editor.js @@ -167,7 +167,7 @@ export default function(element ) { "|", // Separator { name: "guide", - action: "https://simplemde.com/markdown-guide", + action: "https:/"+"/simplemde.com/markdown-guide", className: "image-icon image-icon--editor-help", title: "Howto markdown", }, diff --git a/modules/template_engine/components/html/component_editor/editor.min.js b/modules/template_engine/components/html/component_editor/editor.min.js @@ -0,0 +1,154 @@ +import $ from '../../../../cms/ui/themes/default/script/jquery-global.min.js'; +import Workbench from "../../../../cms/ui/themes/default/script/openrat/workbench.min.js"; +export default function(element ) { +$(element).find('textarea').orAutoheight(); +$(element).find("textarea.or-editor.or-code-editor").each( async function() { +let $editor = $(this); +await Workbench.addStyle ('codemirror-style' ,'./modules/editor/codemirror/lib/codemirror.css'); +await Workbench.addScript('codemirror-script','./modules/editor/codemirror/lib/codemirror.js' ); +let mode = $editor.data('mode'); +let mimetype = $editor.data('mimetype'); +if(mimetype.length>0) +mode = mimetype; +let textareaEl = this; +let editor = CodeMirror.fromTextArea( textareaEl, { +lineNumbers: true, +viewportMargin: Infinity, +mode: mode, +dragDrop: false, +}) +editor.on('change',function() { +let newValue = editor.getValue(); +$(textareaEl).val( newValue ); +} ); +Workbench.getInstance().registerAsDroppable(editor.getWrapperElement(), +(e)=> { +e.stopPropagation(); +e.preventDefault(); +console.debug('dropped',e.dataTransfer); +let pos = editor.getCursor(); +editor.setSelection(pos, pos); +let insertText = e.dataTransfer.getData('id') +let toInsert = ''+insertText; +editor.replaceSelection(toInsert); +} +); +} ); +$(element).find("textarea.or-editor.or-markdown-editor").each( async function() { +await Workbench.addStyle ('simplemde-style' ,'./modules/editor/simplemde/simplemde.min.css'); +await Workbench.addScript('simplemde-script','./modules/editor/simplemde/simplemde.min.js' ); +let textarea = this; +let toolbar = [{ +name: "bold", +action: SimpleMDE.toggleBold, +className: "image-icon image-icon--editor-bold", +title: "Bold", +}, +{ +name: "italic", +action: SimpleMDE.toggleItalic, +className: "image-icon image-icon--editor-italic", +title: "Italic", +}, +{ +name: "heading", +action: SimpleMDE.toggleHeadingBigger, +className: "image-icon image-icon--editor-headline", +title: "Headline", +}, +"|", +{ +name: "quote", +action: SimpleMDE.toggleBlockquote, +className: "image-icon image-icon--editor-quote", +title: "Quote", +}, +{ +name: "code", +action: SimpleMDE.toggleCodeBlock, +className: "image-icon image-icon--editor-code", +title: "Code", +}, +"|", +{ +name: "generic list", +action: SimpleMDE.toggleUnorderedList, +className: "image-icon image-icon--editor-unnumberedlist", +title: "Unnumbered list", +}, +{ +name: "numbered list", +action: SimpleMDE.toggleOrderedList, +className: "image-icon image-icon--editor-numberedlist", +title: "Numbered list", +}, +"|", +{ +name: "table", +action: SimpleMDE.drawTable, +className: "image-icon image-icon--editor-table", +title: "Table", +}, +{ +name: "horizontalrule", +action: SimpleMDE.drawHorizontalRule, +className: "image-icon image-icon--editor-horizontalrule", +title: "Horizontal rule", +}, +"|", +{ +name: "undo", +action: SimpleMDE.undo, +className: "image-icon image-icon--editor-undo", +title: "Undo", +}, +{ +name: "redo", +action: SimpleMDE.redo, +className: "image-icon image-icon--editor-redo", +title: "Redo", +}, +"|", +{ +name: "link", +action: SimpleMDE.drawLink, +className: "image-icon image-icon--editor-link", +title: "Link", +}, +{ +name: "image", +action: SimpleMDE.drawImage, +className: "image-icon image-icon--editor-image", +title: "Image", +}, +"|", +{ +name: "guide", +action: "https:/"+"/simplemde.com/markdown-guide", +className: "image-icon image-icon--editor-help", +title: "Howto markdown", +}, +]; +let mde = new SimpleMDE( +{ +element: $(this)[0], +toolbar: toolbar, +autoDownloadFontAwesome: false +} +); +let codemirror = mde.codemirror; +codemirror.on('change',function() { +let newValue = codemirror.getValue(); +$(textarea).val( newValue ); +} ); +} ); +$(element).find("textarea.or-editor.or-html-editor").each( async function() { +let textarea = this; +await Workbench.addStyle ('trumbowyg-style' ,'./modules/editor/trumbowyg/ui/trumbowyg.css'); +await Workbench.addScript('jquery-slim-script','./modules/cms/ui/themes/default/script/jquery.min.js' ); +let j = jQuery.noConflict(); +await Workbench.addScript('trumbowyg-script' ,'./modules/editor/trumbowyg/trumbowyg.js' ); +j.trumbowyg.svgPath = './modules/editor/trumbowyg/ui/icons.svg'; +j(textarea).trumbowyg(); +} ); +}; +\ No newline at end of file diff --git a/modules/template_engine/components/html/component_group/group.min.js b/modules/template_engine/components/html/component_group/group.min.js @@ -0,0 +1,5 @@ +import Workbench from "../../../../cms/ui/themes/default/script/openrat/workbench.min.js"; +import $ from "../../../../cms/ui/themes/default/script/jquery-global.min.js"; +export default function(element ) { +Workbench.registerOpenClose( $(element).find('.or-collapsible.or-group') ); +}; +\ No newline at end of file diff --git a/modules/template_engine/components/html/component_image/image.min.js b/modules/template_engine/components/html/component_image/image.min.js diff --git a/modules/template_engine/components/html/component_link/link.min.js b/modules/template_engine/components/html/component_link/link.min.js @@ -0,0 +1,4 @@ +import $ from '../../../../cms/ui/themes/default/script/jquery-global.min.js'; +export default function(element ) { +$(element).find('.or-act-clickable').orLinkify(); +}; +\ No newline at end of file diff --git a/modules/template_engine/components/html/component_qrcode/qrcode.min.js b/modules/template_engine/components/html/component_qrcode/qrcode.min.js @@ -0,0 +1,33 @@ +import $ from "../../../../cms/ui/themes/default/script/jquery-global.min.js"; +export default function(element ) { +let createQRCode = async function( value,text) { +let Kjua = (await import("../../../../cms/ui/themes/default/script/tools/kjua.min.js")).default; +let wrapper = $('<div class="or-info-popup or-qrcode-value"></div>'); +let element = Kjua( { +text : text, +render : 'svg', +mode :'label', +label : text, +rounded : 1, +fill : 'currentColor', +back : 'black' +} ); +wrapper.attr('title',''); +wrapper.append( element ); +if ( text ) +wrapper.append('<small class="or-qrcode-text">' + text + '</small>'); +return wrapper; +} +$(element).find('.or-qrcode').click( async function() { +let $element = $(this); +if ( ! $element.children().length ) { +let qrcodeValue = $(element).attr('data-qrcode'); +let qrcodeText = $(element).attr('data-qrcode-text'); +if ( $element.children().length > 0 ) +return; +$element.append( await createQRCode(qrcodeValue,qrcodeText) ); +} +$element.toggleClass('info--open'); +$element.toggleClass('btn--is-active'); +}); +}; +\ No newline at end of file diff --git a/modules/template_engine/components/html/component_table/table.min.js b/modules/template_engine/components/html/component_table/table.min.js @@ -0,0 +1,64 @@ +import $ from '../../../../cms/ui/themes/default/script/jquery-global.min.js'; +export default function(element ) { +let calculateOrderList = function() { +let order = new Array(); +$(element).find('.or-table--sortable').find('tbody > tr.or-data').each(function () { +let objectid = $(this).data('id'); +order.push(objectid); +}); +$(element).find('input[name=order]').val(order.join(',')); +}; +calculateOrderList(); +let sortableElement = $(element).find('.or-table--sortable > tbody').get(0); +if ( sortableElement ) { +let sortable = import( './sortable.min.js' ); +sortable.then( Sortable => { +new Sortable(sortableElement, {onUpdate: calculateOrderList}) +} ); +} +$(element).find('tr.headline > td > input.checkbox').click( function() { +$(this).closest('table').find('tr.or-data > td > input.or-checkbox').attr('checked',Boolean( $(this).attr('checked') ) ); +}); +$(element).find('.or-table-filter > input').keyup( function() { +let filterExpression = $(this).val().toLowerCase(); +let table = $(this).parents('.or-table-wrapper').find('table'); +table.addClass('loader'); +setTimeout( () => { +table.find('tr:not(.or-table-header)').filter(function () { +$(this).toggle($(this).text().toLowerCase().indexOf(filterExpression) > -1) +}) +table.removeClass('loader'); +}, 50); +} ); +$(element).find('table > tbody > tr.or-table-header > td, table > tbody > tr > th').click( function() { +let column = $(this); +let table = column.closest('table'); +table.addClass('loader'); +let isAscending = !column.hasClass('sort-asc'); +table.find('tr.or-table-header > td, tr > th').removeClass('sort-asc').removeClass('sort-desc'); +if ( isAscending ) column.addClass('sort-asc'); else column.addClass('sort-desc'); +Promise.resolve().then( () => { +let rows = table.find('tr:not(.or-table-header)').toArray().sort(comparer(column.index())) +if (!isAscending) { +rows = rows.reverse() +} +for (let i = 0; i < rows.length; i++) { +table.append( $(rows[i]) ); +} +table.removeClass('loader'); +}); +} ); +function comparer(index) { +return function(a, b) { +let valA = getCellValue(a, index), valB = getCellValue(b, index) +return isNumeric(valA) && isNumeric(valB) ? valA - valB : valA.toString().localeCompare(valB) +} +} +function getCellValue(row, index) { +let x = $(row).children('td').eq(index); +return $(row).children('td').eq(index).text(); +} +function isNumeric(n) { +return !isNaN(parseFloat(n)) && isFinite(n); +} +}; +\ No newline at end of file diff --git a/modules/template_engine/components/html/component_upload/upload.js b/modules/template_engine/components/html/component_upload/upload.js @@ -1,4 +1,3 @@ -import Workbench from "../../../../cms/ui/themes/default/script/openrat/workbench.js"; import Api from "../../../../cms/ui/themes/default/script/openrat/api.js"; import $ from "../../../../cms/ui/themes/default/script/jquery-global.js"; @@ -27,7 +26,7 @@ export default function (element ) { let files = e.originalEvent.dataTransfer.files; //We need to send dropped files to Server - Workbench.handleFileUpload(form,files); + handleFileUpload(form,files); }); @@ -36,7 +35,7 @@ export default function (element ) { let files = this.files; - Workbench.handleFileUpload(form,files); + handleFileUpload(form,files); }); }; @@ -47,7 +46,7 @@ export default function (element ) { * @param form * @param files */ -Workbench.handleFileUpload = function(form,files) +let handleFileUpload = function(form,files) { for (let i = 0; i < files.length; i++) { diff --git a/modules/template_engine/components/html/component_upload/upload.min.js b/modules/template_engine/components/html/component_upload/upload.min.js @@ -0,0 +1,44 @@ +import Api from "../../../../cms/ui/themes/default/script/openrat/api.min.js"; +import $ from "../../../../cms/ui/themes/default/script/jquery-global.min.js"; +export default function (element ) { +let form = $(element).find('form'); +let dropzone = $(element).find('div.or-dropzone-upload'); +dropzone.on('dragenter', function (e) +{ +e.stopPropagation(); +e.preventDefault(); +$(this).css('border', '1px dotted gray'); +}); +dropzone.on('dragover', function (e) +{ +e.stopPropagation(); +e.preventDefault(); +}); +dropzone.on('drop', function (e) +{ +$(this).css('border','1px dotted red'); +e.preventDefault(); +let files = e.originalEvent.dataTransfer.files; +handleFileUpload(form,files); +}); +$(element).find('input[type=file]').change( function() { +let files = this.files; +handleFileUpload(form,files); +}); +}; +let handleFileUpload = function(form,files) +{ +for (let i = 0; i < files.length; i++) +{ +let f = files[i]; +let form_data = new FormData(); +form_data.append('file' , f); +form_data.append('action' , $(form).data('action')); +form_data.append('subaction', $(form).data('method')); +form_data.append('token' , $(form).find('input[name=token]').val() ); +form_data.append('id' , $(form).find('input[name=id]' ).val() ); +form_data.append('output' , 'json' ); +let api = new Api(); +api.sendData( form_data ); +} +} +\ No newline at end of file diff --git a/modules/util/JSMinifier.class.php b/modules/util/JSMinifier.class.php @@ -0,0 +1,49 @@ +<?php + +namespace util; + +class JSMinifier +{ + const FLAG_IMPORT_MIN_JS = 1; + const FLAG_REMOVE_MULTILINE_COMMENT = 2; + const FLAG_REMOVE_BLANK_LINES = 4; + const FLAG_REMOVE_LINE_COMMENTS = 8; + const FLAG_REMOVE_WHITESPACE = 16; + const FLAG_REMOVE_LINEBREAK = 32; + const FLAG_REMOVE_TABS = 64; + const FLAG_REMOVE_SUPERFLOUS_SPACES = 128; + const FLAG_ALL = 255; + + const REPLACER = [ + self::FLAG_REMOVE_MULTILINE_COMMENT => ["/\/\*[\s\S]*?\*\//" , '' ], + self::FLAG_REMOVE_LINE_COMMENTS => ["/^(.*)\/\/.*$/m" ,'${1}' ], + self::FLAG_REMOVE_BLANK_LINES => ['/^\n+|^[\t\s]*\n+/m' , '' ], + self::FLAG_IMPORT_MIN_JS => ['/^(import.*from.*)\.js(.*)$/m','${1}.min.js${2}' ], + self::FLAG_REMOVE_WHITESPACE => ['/^\s*(.*)\s*$/m' ,'${1}' ], + self::FLAG_REMOVE_LINEBREAK => ['/\n/' ,'' ], + self::FLAG_REMOVE_TABS => ['/\t/' ,'' ], + self::FLAG_REMOVE_SUPERFLOUS_SPACES => ['/\s{2,}7' ,' ' ], + ]; + + /** + * Which flags are enabled? + * @var int + */ + public $config = self::FLAG_ALL; + + public function __construct( $flags = null ) + { + if ( $flags ) + $this->config = $flags; + } + + + public function minify( $code ) { + foreach( self::REPLACER as $flag => $replacer ) + if ( $this->config & $flag ) { + list( $replace, $with ) = $replacer; + $code = preg_replace( $replace, $with, $code ); + } + return $code; + } +} +\ No newline at end of file