[!!!][FEATURE] Refactor EXT:t3editor 13/53413/39
authorAndreas Fernandez <a.fernandez@scripting-base.de>
Wed, 5 Jul 2017 18:25:53 +0000 (20:25 +0200)
committerAndreas Fernandez <typo3@scripting-base.de>
Thu, 17 Aug 2017 18:27:27 +0000 (20:27 +0200)
EXT:t3editor is refactored to use the latest CodeMirror version (at the
time of writing it's 5.28.0).
Developers are now able to easily register and use custom modes for syntax
highlighting. Also, addons for CodeMirror can be added easily.

As CodeMirror provides these already, some useful addons are already
registered, for example a search with hit annotations, fullscreen mode and
jump-to-line functionality. A positive side-effect is that a lot of custom
code was removed.

Since the architecture allows to register additional modes, the TypoScript
mode has been refactored and might be moved into a separate extension in
further iterations.

Resolves: #81901
Releases: master
Change-Id: I432d1fdb3ba1f2a0b9246207dd70843b4bdbfbd9
Reviewed-on: https://review.typo3.org/53413
Reviewed-by: Frank Naegler <frank.naegler@typo3.org>
Tested-by: Frank Naegler <frank.naegler@typo3.org>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Tested-by: Andreas Fernandez <typo3@scripting-base.de>
428 files changed:
Build/Gruntfile.js
Build/Resources/Public/Sass/editor.scss
Build/Resources/Public/Sass/editor/_colors.scss [deleted file]
Build/Resources/Public/Sass/editor_inner.scss [deleted file]
Build/Resources/Public/Sass/editor_typoscript_colors.scss [deleted file]
Build/package-lock.json
Build/package.json
Build/types/TYPO3/index.d.ts
composer.json
typo3/sysext/backend/Classes/Form/FormResultCompiler.php
typo3/sysext/core/Documentation/Changelog/master/Breaking-81901-ChangedBehaviorOfAutocompletionAppearance.rst [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/master/Breaking-81901-RemovedExplanationOfTypoScriptOptions.rst [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/master/Feature-81901-ExtendT3editor.rst [new file with mode: 0644]
typo3/sysext/t3editor/Classes/Addon.php [new file with mode: 0644]
typo3/sysext/t3editor/Classes/Exception/InvalidModeException.php [new file with mode: 0644]
typo3/sysext/t3editor/Classes/Form/Element/T3editorElement.php
typo3/sysext/t3editor/Classes/Hook/FileEditHook.php
typo3/sysext/t3editor/Classes/Mode.php [new file with mode: 0644]
typo3/sysext/t3editor/Classes/Registry/AddonRegistry.php [new file with mode: 0644]
typo3/sysext/t3editor/Classes/Registry/ModeRegistry.php [new file with mode: 0644]
typo3/sysext/t3editor/Classes/T3editor.php
typo3/sysext/t3editor/Classes/TypoScriptReferenceLoader.php
typo3/sysext/t3editor/Configuration/Backend/AjaxRoutes.php
typo3/sysext/t3editor/Configuration/Backend/T3editor/Addons.php [new file with mode: 0644]
typo3/sysext/t3editor/Configuration/Backend/T3editor/Modes.php [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Private/Templates/t3editor.html [deleted file]
typo3/sysext/t3editor/Resources/Private/TypeScript/T3editor.ts [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/Css/t3editor.css
typo3/sysext/t3editor/Resources/Public/Css/t3editor_inner.css [deleted file]
typo3/sysext/t3editor/Resources/Public/Css/t3editor_typoscript_colors.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/CompletionResult.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/TsCodeCompletion.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/TsParser.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/TsRef.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/TypoScriptHint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/AUTHORS [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/CHANGELOG.md [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/CONTRIBUTING.md [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/LICENSE [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/README.md [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/comment/comment.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/comment/continuecomment.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/dialog/dialog.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/dialog/dialog.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/display/autorefresh.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/display/fullscreen.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/display/fullscreen.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/display/panel.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/display/placeholder.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/display/rulers.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/edit/closebrackets.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/edit/closetag.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/edit/continuelist.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/edit/matchbrackets.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/edit/matchtags.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/edit/trailingspace.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/fold/brace-fold.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/fold/comment-fold.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/fold/foldcode.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/fold/foldgutter.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/fold/foldgutter.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/fold/indent-fold.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/fold/markdown-fold.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/fold/xml-fold.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/hint/anyword-hint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/hint/css-hint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/hint/html-hint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/hint/javascript-hint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/hint/show-hint.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/hint/show-hint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/hint/sql-hint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/hint/xml-hint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/lint/coffeescript-lint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/lint/css-lint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/lint/html-lint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/lint/javascript-lint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/lint/json-lint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/lint/lint.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/lint/lint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/lint/yaml-lint.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/merge/merge.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/merge/merge.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/mode/loadmode.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/mode/multiplex.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/mode/multiplex_test.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/mode/overlay.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/mode/simple.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/runmode/colorize.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/runmode/runmode-standalone.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/runmode/runmode.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/runmode/runmode.node.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/scroll/annotatescrollbar.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/scroll/scrollpastend.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/scroll/simplescrollbars.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/scroll/simplescrollbars.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/search/jump-to-line.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/search/match-highlighter.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/search/matchesonscrollbar.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/search/matchesonscrollbar.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/search/search.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/search/searchcursor.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/selection/active-line.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/selection/mark-selection.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/selection/selection-pointer.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/tern/tern.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/tern/tern.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/tern/worker.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/wrap/hardwrap.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/keymap/emacs.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/keymap/sublime.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/keymap/vim.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/lib/codemirror.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/lib/codemirror.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/apl/apl.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/asciiarmor/asciiarmor.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/asn.1/asn.1.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/asterisk/asterisk.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/brainfuck/brainfuck.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/clike/clike.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/clojure/clojure.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/cmake/cmake.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/cobol/cobol.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/coffeescript/coffeescript.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/commonlisp/commonlisp.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/crystal/crystal.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/css/css.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/cypher/cypher.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/d/d.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/dart/dart.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/diff/diff.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/django/django.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/dockerfile/dockerfile.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/dtd/dtd.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/dylan/dylan.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/ebnf/ebnf.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/ecl/ecl.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/eiffel/eiffel.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/elm/elm.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/erlang/erlang.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/factor/factor.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/fcl/fcl.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/forth/forth.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/fortran/fortran.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/gas/gas.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/gfm/gfm.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/gherkin/gherkin.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/go/go.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/groovy/groovy.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/haml/haml.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/handlebars/handlebars.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/haskell-literate/haskell-literate.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/haskell/haskell.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/haxe/haxe.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/htmlembedded/htmlembedded.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/htmlmixed/htmlmixed.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/http/http.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/idl/idl.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/javascript/javascript.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/jinja2/jinja2.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/jsx/jsx.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/julia/julia.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/livescript/livescript.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/lua/lua.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/markdown/markdown.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/mathematica/mathematica.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/mbox/mbox.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/meta.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/mirc/mirc.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/mllike/mllike.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/modelica/modelica.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/mscgen/mscgen.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/mumps/mumps.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/nginx/nginx.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/nsis/nsis.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/ntriples/ntriples.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/octave/octave.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/oz/oz.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/pascal/pascal.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/pegjs/pegjs.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/perl/perl.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/php/php.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/pig/pig.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/powershell/powershell.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/properties/properties.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/protobuf/protobuf.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/pug/pug.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/puppet/puppet.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/python/python.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/q/q.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/r/r.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/rpm/changes/index.html [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/rpm/rpm.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/rst/rst.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/ruby/ruby.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/rust/rust.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/sas/sas.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/sass/sass.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/scheme/scheme.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/shell/shell.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/sieve/sieve.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/slim/slim.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/smalltalk/smalltalk.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/smarty/smarty.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/solr/solr.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/soy/soy.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/sparql/sparql.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/spreadsheet/spreadsheet.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/sql/sql.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/stex/stex.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/stylus/stylus.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/swift/swift.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/tcl/tcl.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/textile/textile.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/tiddlywiki/tiddlywiki.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/tiddlywiki/tiddlywiki.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/tiki/tiki.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/tiki/tiki.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/toml/toml.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/tornado/tornado.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/troff/troff.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/ttcn-cfg/ttcn-cfg.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/ttcn/ttcn.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/turtle/turtle.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/twig/twig.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/vb/vb.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/vbscript/vbscript.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/velocity/velocity.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/verilog/verilog.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/vhdl/vhdl.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/vue/vue.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/webidl/webidl.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/xml/xml.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/xquery/xquery.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/yacas/yacas.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/yaml-frontmatter/yaml-frontmatter.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/yaml/yaml.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/mode/z80/z80.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/package.json [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/rollup.config.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/codemirror.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/Display.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/focus.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/gutters.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/highlight_worker.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/line_numbers.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/mode_state.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/operations.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/scroll_events.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/scrollbars.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/scrolling.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/selection.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/update_display.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/update_line.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/update_lines.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/display/view_tracking.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/edit/CodeMirror.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/edit/commands.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/edit/deleteNearSelection.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/edit/drop_events.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/edit/fromTextArea.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/edit/global_events.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/edit/key_events.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/edit/legacy.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/edit/main.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/edit/methods.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/edit/mouse_events.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/edit/options.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/edit/utils.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/input/ContentEditableInput.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/input/TextareaInput.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/input/indent.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/input/input.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/input/keymap.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/input/keynames.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/input/movement.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/line/highlight.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/line/line_data.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/line/pos.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/line/saw_special_spans.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/line/spans.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/line/utils_line.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/measurement/position_measurement.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/measurement/widgets.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/model/Doc.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/model/change_measurement.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/model/changes.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/model/chunk.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/model/document_data.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/model/history.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/model/line_widget.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/model/mark_text.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/model/selection.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/model/selection_updates.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/modes.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/util/StringStream.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/util/bidi.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/util/browser.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/util/dom.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/util/event.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/util/feature_detection.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/util/misc.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/src/util/operation_group.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/3024-day.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/3024-night.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/abcdef.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/ambiance-mobile.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/ambiance.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/base16-dark.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/base16-light.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/bespin.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/blackboard.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/cobalt.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/colorforth.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/dracula.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/duotone-dark.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/duotone-light.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/eclipse.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/elegant.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/erlang-dark.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/hopscotch.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/icecoder.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/isotope.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/lesser-dark.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/liquibyte.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/material.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/mbo.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/mdn-like.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/midnight.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/monokai.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/neat.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/neo.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/night.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/panda-syntax.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/paraiso-dark.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/paraiso-light.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/pastel-on-dark.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/railscasts.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/rubyblue.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/seti.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/solarized.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/the-matrix.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/tomorrow-night-bright.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/tomorrow-night-eighties.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/ttcn.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/twilight.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/vibrant-ink.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/xq-dark.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/xq-light.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/yeti.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/theme/zenburn.css [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/LICENSE [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/VERSION_0.94 [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/csharp/css/csharpcolors.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/csharp/index.html [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/csharp/js/parsecsharp.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/csharp/js/tokenizecsharp.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/lua/LICENSE [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/lua/css/luacolors.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/lua/index.html [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/lua/js/parselua.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/ometa/LICENSE [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/ometa/css/ometacolors.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/ometa/index.html [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/ometa/js/parseometa.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/ometa/js/tokenizeometa.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/php/LICENSE [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/php/css/phpcolors.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/php/index.html [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/php/js/parsephp.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/php/js/parsephphtmlmixed.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/php/js/tokenizephp.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/plsql/LICENSE [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/plsql/css/plsqlcolors.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/plsql/index.html [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/plsql/js/parseplsql.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/python/LICENSE [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/python/css/pythoncolors.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/python/index.html [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/python/js/parsepython.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/scheme/LICENSE [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/scheme/css/schemecolors.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/scheme/index.html [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/scheme/js/parsescheme.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/scheme/js/tokenizescheme.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/sql/LICENSE [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/sql/css/sqlcolors.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/sql/index.html [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/contrib/sql/js/parsesql.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/css/baboon.png [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/css/baboon_vector.ai [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/css/csscolors.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/css/docs.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/css/font.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/css/jscolors.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/css/people.jpg [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/css/sparqlcolors.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/css/xmlcolors.css [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/codemirror.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/editor.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/highlight.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/mirrorframe.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/parsecss.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/parsedummy.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/parsehtmlmixed.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/parsejavascript.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/parsesparql.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/parsexml.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/select.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/stringstream.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/tokenize.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/tokenizejavascript.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/undo.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/unittests.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/util.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/unittests.html [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Mode/typoscript/typoscript.js [new file with mode: 0644]
typo3/sysext/t3editor/Resources/Public/JavaScript/Plugins/CodeCompletion/CompletionResult.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Plugins/CodeCompletion/DescriptionPlugin.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Plugins/CodeCompletion/TsCodeCompletion.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Plugins/CodeCompletion/TsParser.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/Plugins/CodeCompletion/TsRef.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/T3editor.js
typo3/sysext/t3editor/Resources/Public/JavaScript/parse_typoscript/parsetyposcript.js [deleted file]
typo3/sysext/t3editor/Resources/Public/JavaScript/parse_typoscript/tokenizetyposcript.js [deleted file]
typo3/sysext/t3editor/Tests/Unit/Registry/AddonRegistryTest.php [new file with mode: 0644]
typo3/sysext/t3editor/Tests/Unit/Registry/ModeRegistryTest.php [new file with mode: 0644]
typo3/sysext/t3editor/composer.json
typo3/sysext/t3editor/ext_localconf.php

index 29345ec..fd2be03 100644 (file)
@@ -126,9 +126,7 @@ module.exports = function (grunt) {
                        },
                        t3editor: {
                                files: {
-                                       '<%= paths.t3editor %>Public/Css/t3editor.css': '<%= paths.sass %>editor.scss',
-                                       '<%= paths.t3editor %>Public/Css/t3editor_inner.css': '<%= paths.sass %>editor_inner.scss',
-                                       '<%= paths.t3editor %>Public/Css/t3editor_typoscript_colors.css': '<%= paths.sass %>editor_typoscript_colors.scss'
+                                       '<%= paths.t3editor %>Public/Css/t3editor.css': '<%= paths.sass %>editor.scss'
                                }
                        }
                },
@@ -186,7 +184,7 @@ module.exports = function (grunt) {
                                src: '<%= paths.linkvalidator %>Public/Css/*.css'
                        },
                        t3editor: {
-                               src: '<%= paths.t3editor %>Public/Css/*.css'
+                               src: '<%= paths.t3editor %>Public/Css/**/*.css'
                        },
                        workspaces: {
                                src: '<%= paths.workspaces %>Public/Css/*.css'
@@ -409,6 +407,14 @@ module.exports = function (grunt) {
                                        'lang/': 'ckeditor/lang/'
                                }
                        },
+                       t3editor: {
+                               options: {
+                                       destPrefix: "<%= paths.t3editor %>Public/JavaScript/Contrib"
+                               },
+                               files: {
+                                       'cm/': 'codemirror/'
+                               }
+                       },
                        all: {
                                options: {
                                        destPrefix: "<%= paths.core %>Public/JavaScript/Contrib"
index 10caac3..6ba1bb1 100644 (file)
 // Description: Global styles for t3editor wrapper.
 //
 
-// Include Color Variables
-@import 'editor/colors';
+$panel-bg-color: #f7f7f7;
+$panel-border-color: #ddd;
+$fullscreen-top: 64px;
+$panel-font-size: 0.85em;
+$panel-padding-vertical: 3px;
+$panel-padding-horizontal: 6px;
+$color-matching-bracket: #6ca52b;
 
-// T3editor styles
-.CodeMirror-wrapping {
-    position: relative;
-    min-width: 100%;
-
-    div {
-        line-height: 13px !important;
-    }
-}
-
-div.CodeMirror-line-numbers {
-    margin-right: 2px;
-    padding-right: 3px;
-    padding-left: 3px;
-    font-size: 10px;
-    text-align: right;
-    line-height: 13px !important;
-}
-
-.TSREF_type_label,
-.TSREF_description_label {
-    font-weight: bold;
-}
-
-#TSREF_description {
-    margin-bottom: 5px;
+.CodeMirror-fullscreen {
+    top: $fullscreen-top;
 }
 
-// Code complete box
-.t3e_codeCompleteBox {
-    border: 1px solid $color-t3-gray-light;
-    padding: 0;
-    background-color: $color-t3-gray-superlight;
-
-    ul {
-        margin: 0;
-        padding: 0;
-        list-style-type: none;
-
-        li {
-            padding-left: 2px;
-            padding-right: 2px;
-            cursor: pointer;
-
-            &.active {
-                padding-left: 2px;
-                padding-right: 2px;
-                background-color: $color-white;
-            }
-
-            span {
-                &.word_undefined,
-                &.word_definedTSREFProperty,
-                &.word_undefinedTSREFProperty {
-                    font-family: monospace;
-                }
-
-                &.word_undefined,
-                &.word_definedTSREFProperty {
-                    color: $color-t3-red;
-                }
-
-                &.word_undefinedTSREFProperty {
-                    color: $color-t3-blue;
-                }
+.CodeMirror-panel {
+    background: $panel-bg-color;
+    padding: $panel-padding-vertical $panel-padding-horizontal;
+    font-size: $panel-font-size;
 
-                &.word_userProperty {
-                    font-size: 12px;
-                    color: $gray;
-                }
-            }
-        }
+    &-bottom {
+        border-top: 1px solid $panel-border-color;
     }
 }
 
-// Code description box
-.t3e_descriptionBox {
-    position: absolute;
-    top: 0;
-    left: 0;
-    z-index: 190;
-    border: 1px solid $color-t3-gray-light;
-    padding: 2px 5px;
-    height: 220px;
-    width: 260px;
-    background-color: $color-t3-gray-superlight;
-}
-
-.t3e_toolbar {
-    position: absolute;
-    top: 0;
-    right: 50px;
-    width: 200px;
-}
-
-.t3e_toolbar_icon {
-    border: 1px solid $color-t3-gray-light;
-    float: left;
-    width: 20px;
-    height: 20px;
-}
-
-.t3e_codeCompleteWrap {
-    position: absolute;
-    top: 0;
-    left: 0;
-    z-index: 190;
-}
-
-// Around the editor
-.t3e_wrap {
-    position: relative;
-    border: 1px solid $color-t3-gray-light;
-    min-width: 100%;
-    background-color: $color-t3-gray-superlight;
-}
-
-.t3e_modalOverlay {
-    position: absolute;
-    top: 0;
-    left: 0;
-    background-color: $color-t3-gray-superlight;
-    z-index: 200;
-    width: 100%;
-    height: 100%;
-    text-align: center;
-}
-
-.t3e_fullscreen {
-    position: absolute;
-    top: 0;
-    left: 0;
-    z-index: 999;
-}
-
-.t3e_iframe_wrap {
-    margin: 0 0 0 3px;
-}
-
-.t3e_iframe {
-    display: block;
-    padding: 0;
-}
-
-.t3e_toolbar_wrap {
-    clear: both;
-    padding-right: 20px;
-    width: 100%;
-    font-size: 11px;
-}
-
-.t3e_statusbar_wrap {
-    position: absolute;
-    left: 0;
-    bottom: 0;
-    padding: 2px 5px;
-    height: 20px;
-    width: 100%;
-    font-size: 11px;
-    background-color: $color-t3-gray;
-}
-
-.t3e_statusbar_wrap {
-    span {
-        margin: 3px;
-        color: $color-white;
-    }
-}
-
-.t3e_statusbar_item {
-    float: right;
-    height: 16px;
-    border-left: 1px solid gray;
-    padding: 4px 14px 0;
-}
-
-.t3e_clickable {
-    cursor: hand;
-}
-
-.t3e_statusbar_overlay {
-    position: absolute;
-    bottom: 20px;
-    right: 17px;
-    z-index: 100;
-    opacity: 0.85;
-    border-left: 1px solid gray;
-    border-right: 1px solid gray;
-    border-top: 1px solid gray;
-    padding: 5px 0 10px;
-    width: 180px;
-    height: 70%;
-    background-color: $color-t3-gray-superlight;
-
-    &#t3e_statusbar_overlay_options {
-        height: 8em;
+div.CodeMirror {
+    span.CodeMirror-matchingbracket {
+        color: $color-matching-bracket;
     }
-
-    ul {
-        margin: 0;
-        padding: 0;
-        list-style-type: none;
-
-        li {
-            cursor: hand;
-            padding: 2px 6px;
-            color: $text-color;
-
-            &:hover {
-                background-color: $color-t3-gray-superlight;
-            }
-
-            label {
-                cursor: pointer;
-            }
-        }
-    }
-}
-
-#t3e_modalOverlay_help {
-    top: 10%;
-    left: 5%;
-    height: 80%;
-    width: 90%;
-    border: 1px solid $gray;
-    padding: 10px;
-    background-image: none;
-}
-
-.t3e_footeritem_active {
-    background-color: $color-t3-gray-superlight;
 }
diff --git a/Build/Resources/Public/Sass/editor/_colors.scss b/Build/Resources/Public/Sass/editor/_colors.scss
deleted file mode 100644 (file)
index a5c8f0f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// LESS Variables for Colors
-// -------------------------
-// Description: Styles for t3editor text area.
-//
-
-// TYPO3 corporate design
-$color-t3-primary: #ff8700;
-$color-t3-gray-superlight: #f4f4f4;
-$color-t3-gray-light: #b9b9b9;
-$color-t3-gray: #8c8c8c;
-$color-t3-gray-dark: #515151;
-$color-t3-green: #5abc55;
-$color-t3-yellow: #ffc800;
-$color-t3-red: #dd123d;
-$color-t3-blue: #0080ff;
-
-// Bootstrap
-$gray-darker: rgb(30, 30, 30);
-$gray-dark: rgb(90, 90, 90);
-$gray: rgb(115, 115, 115);
-$gray-light: rgb(215, 215, 215);
-$gray-lighter: rgb(245, 245, 245);
-$brand-primary: #0078e6;
-$brand-success: #79a548;
-$brand-info: #6daae0;
-$brand-warning: #e8a33d;
-$brand-danger: #c83c3c;
-$brand-notice: #333;
-
-// Fonts
-$text-color: #000;
-
-// Custom
-$color-white: #fff;
-$color-yellow-light: #ffc857;
-$color-green-dark: darkgreen;
-$color-red-dark: maroon;
diff --git a/Build/Resources/Public/Sass/editor_inner.scss b/Build/Resources/Public/Sass/editor_inner.scss
deleted file mode 100644 (file)
index 08dac73..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-//
-// T3editor Inner Styles
-// ---------------------
-// Description: Styles for t3editor text area.
-//              The compiled CSS file is included in T3editor.php & T3editorElement.php
-//
-
-// Include Color Variables
-@import 'editor/colors';
-
-// T3editor inner styles
-.editbox {
-    border-width: 0;
-    margin: 1px 0 0 0.3em;
-    padding: 0;
-    font-family: monospace;
-    font-size: 12px;
-    color: $text-color;
-    line-height: 13px;
-    white-space: nowrap;
-    background-color: $color-white;
-}
diff --git a/Build/Resources/Public/Sass/editor_typoscript_colors.scss b/Build/Resources/Public/Sass/editor_typoscript_colors.scss
deleted file mode 100644 (file)
index 835ca6b..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-//
-// T3editor TypoScript Font Styles
-// -------------------------------
-// Description: Syntax highlighting for TypoScript.
-//              The compiled CSS file is included in T3editor.php & T3editorElement.php
-//
-
-// Include Color Variables
-@import 'editor/colors';
-
-// Text color styles
-.other {
-    color: $text-color;
-}
-
-.ts-value {
-    color: $color-t3-red;
-}
-
-.ts-operator,
-.ts-objstr,
-.keyword,
-.keyword2,
-.keyword3,
-.reserved {
-    color: $color-t3-blue;
-}
-
-.ts-operator {
-    font-weight: bold;
-}
-
-.ts-value_copy {
-    color: $color-green-dark;
-}
-
-.ts-value_unset,
-.ts-ignored,
-.ts-default {
-    background-color: $color-t3-green;
-}
-
-.ts-comment {
-    font-style: italic;
-    color: $gray;
-}
-
-.ts-condition {
-    font-weight: bold;
-    color: $color-white;
-    background-color: $color-red-dark;
-}
-
-.ts-error {
-    border: 1px $color-t3-red dashed;
-    font-weight: bold;
-    background-color: $color-t3-yellow;
-}
-
-.highlight-bracket {
-    color: $color-white;
-    background-color: $color-t3-green;
-}
-
-.error-bracket {
-    color: $color-white;
-    background-color: $color-t3-red;
-}
-
-// Unparsed code
-pre.code,
-.editbox {
-    color: $gray;
-}
index 687d0f8..b14b757 100644 (file)
       "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
       "dev": true
     },
+    "codemirror": {
+      "version": "5.28.0",
+      "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.28.0.tgz",
+      "integrity": "sha512-E/Z6050shti9v9ivl0dUClVRM4xaH204jsJmEpNYC6KDTlQwAz+5DdhLzn0tjaL/Mp1P0J1uhZokcSP2RFSwlA==",
+      "dev": true
+    },
     "coffee-script": {
       "version": "1.10.0",
       "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.10.0.tgz",
index b9b6519..82af3e9 100644 (file)
@@ -24,6 +24,7 @@
     "bootstrap-slider": "^9.8.0",
     "chosen-js": "^1.7.0",
     "ckeditor": "^4.7.1",
+    "codemirror": "^5.28.0",
     "cropper": "^2.3.4",
     "d3": "^4.9.1",
     "datatables": "^1.10.13",
index d71ce15..d1054fd 100644 (file)
@@ -69,3 +69,5 @@ declare module 'TYPO3/CMS/Core/Contrib/imagesloaded.pkgd.min' {
   import * as imagesloaded from 'imagesloaded';
   export = imagesloaded;
 }
+
+declare module 'cm/lib/codemirror';
index 24977e3..d7166ae 100644 (file)
                        "TYPO3\\CMS\\SysAction\\Tests\\": "typo3/sysext/sys_action/Tests/",
                        "TYPO3\\CMS\\SysNote\\Tests\\": "typo3/sysext/sys_note/Tests/",
                        "TYPO3\\CMS\\Workspaces\\Tests\\": "typo3/sysext/workspaces/Tests/",
-                       "TYPO3\\CMS\\Recycler\\Tests\\": "typo3/sysext/recycler/Tests/"
+                       "TYPO3\\CMS\\Recycler\\Tests\\": "typo3/sysext/recycler/Tests/",
+                       "TYPO3\\CMS\\T3editor\\Tests\\": "typo3/sysext/t3editor/Tests/"
                },
                "classmap": ["typo3/sysext/extbase/Tests/Unit/Object/Container/Fixtures/"]
        }
index cfa99db..104938e 100644 (file)
@@ -18,7 +18,6 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Utility\ArrayUtility;
-use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -267,10 +266,6 @@ class FormResultCompiler
                 $pageRenderer->addInlineLanguageLabelFile($additionalInlineLanguageLabelFile);
             }
         }
-        // Load codemirror for T3Editor
-        if (ExtensionManagementUtility::isLoaded('t3editor')) {
-            $pageRenderer->addJsFile('EXT:t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/codemirror.js');
-        }
         // We want to load jQuery-ui inside our js. Enable this using requirejs.
         $pageRenderer->addJsFile('EXT:backend/Resources/Public/JavaScript/jsfunc.inline.js');
 
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-81901-ChangedBehaviorOfAutocompletionAppearance.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-81901-ChangedBehaviorOfAutocompletionAppearance.rst
new file mode 100644 (file)
index 0000000..067d8bf
--- /dev/null
@@ -0,0 +1,28 @@
+.. include:: ../../Includes.txt
+
+=================================================================
+Breaking: #81901 - Changed behavior of auto-completion appearance
+=================================================================
+
+See :issue:`81901`
+
+Description
+===========
+
+Due to streamlining t3editor's JavaScript code to CodeMirror's architecture, the behavior of the TS auto-completion
+has changed.
+
+
+Impact
+======
+
+After pressing the dot character (.), the auto-completion does not appear automatically. A user has to press the
+keystroke Ctrl+Space now.
+
+
+Affected Installations
+======================
+
+All installations are affected.
+
+.. index:: Backend, NotScanned
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-81901-RemovedExplanationOfTypoScriptOptions.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-81901-RemovedExplanationOfTypoScriptOptions.rst
new file mode 100644 (file)
index 0000000..c01e3ba
--- /dev/null
@@ -0,0 +1,26 @@
+.. include:: ../../Includes.txt
+
+============================================================
+Breaking: #81901 - Removed explanation of TypoScript options
+============================================================
+
+See :issue:`81901`
+
+Description
+===========
+
+The explanation of TypoScript options displayed with autocompletion has been removed.
+
+
+Impact
+======
+
+Using the autocompletion will not render the description of the TypoScript Reference anymore.
+
+
+Affected Installations
+======================
+
+All installations are affected.
+
+.. index:: Backend, NotScanned
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-81901-ExtendT3editor.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-81901-ExtendT3editor.rst
new file mode 100644 (file)
index 0000000..8d10fe3
--- /dev/null
@@ -0,0 +1,103 @@
+.. include:: ../../Includes.txt
+
+=================================
+Feature: #81901 - Extend T3editor
+=================================
+
+See :issue:`81901`
+
+Description
+===========
+
+Since the refactoring of EXT:t3editor, custom modes (used for syntax highlighting) and addons can be registered now.
+
+Prerequisites
+-------------
+
+To do this, extensions may have now these two files to feed T3editor:
+
+* Configuration/Backend/T3editor/Addons.php
+* Configuration/Backend/T3editor/Modes.php
+
+Both files return an array, as known as in TCA and Backend Routes, for example.
+
+
+Register an addon
+-----------------
+
+To register an addon, the following code may be used:
+
+.. code-block:: php
+    'my/addon' => [
+        'module' => 'cm/addon/my/addon',
+        'cssFiles' => [
+            'EXT:my_extension/Resources/Public/Css/MyAddon.css',
+        ],
+        'options' [
+            'foobar' => 'baz',
+        ],
+        'modes' => ['htmlmixed', 'xml'],
+    ],
+
+
++--------------+--------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| Key          | Type   | Description                                                                                                                                                                 |
++==============+========+=============================================================================================================================================================================+
+| <identifier> | string | Represents the unique identifier of the module (`my/addon` in this example)                                                                                                 |
++==============+========+=============================================================================================================================================================================+
+| module       | string | Mandatory: Holds the RequireJS namespace of the CodeMirror module. For custom modules placed in an extension, the known `TYPO3/CMS/Extension/Module` namespace must be used |
++==============+========+=============================================================================================================================================================================+
+| cssFiles     | array  | Holds all CSS files that must be loaded for the module                                                                                                                      |
++==============+========+=============================================================================================================================================================================+
+| options      | array  | Options that are used by the addon                                                                                                                                          |
++==============+========+=============================================================================================================================================================================+
+| modes        | array  | "Jails" the addon to specific modes. This means, the module is only loaded if any of the given modes is used                                                                |
++-----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
+Register a mode
+---------------
+
+To register a mode, the following code may be used:
+
+.. code-block:: php
+    'css' => [
+        'module' => 'cm/mode/css/css',
+        'extensions' => ['css'],
+    ],
+
+
++--------------+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| Key          | Type   | Description                                                                                                                                                             |
++==============+========+=========================================================================================================================================================================+
+| <identifier> | string | Represents the unique identifier and format code of the mode (`css` in this example). The format code is used in TCA to define the CodeMirror mode to be used           |
++==============+========+=========================================================================================================================================================================+
+| module       | string | Mandatory: Holds the RequireJS namespace of the CodeMirror mode. For custom modules placed in an extension, the known `TYPO3/CMS/Extension/Mode` namespace must be used |
++==============+========+=========================================================================================================================================================================+
+| extensions   | array  | Binds the mode to specific file extension. This is important for using T3editor in the Filelist module.                                                                 |
++==============+========+=========================================================================================================================================================================+
+| default      | bool   | If set, the mode is used as fallback if no sufficient mode is available. By factory default, the default mode is `html`                                                 |
++-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
+CodeMirror delivers a lot more modes and addons than registered in T3editor by default.
+More supported addons and modes are available at:
+
+* https://github.com/codemirror/CodeMirror/tree/5.27.4/addon
+* https://github.com/codemirror/CodeMirror/tree/5.27.4/mode
+
+
+Impact
+======
+
+After clearing the system caches of TYPO3, T3editor checks every extension for the files `Configuration/Backend/T3editor/Addons.php`
+and `Configuration/Backend/T3editor/Modes.php`. The complete configuration of both is built and stored in the cache
+afterwards.
+
+
+Affected Installations
+======================
+
+All installations are affected.
+
+.. index:: Backend
diff --git a/typo3/sysext/t3editor/Classes/Addon.php b/typo3/sysext/t3editor/Classes/Addon.php
new file mode 100644 (file)
index 0000000..723b6ed
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\T3editor;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Represents an addon for CodeMirror
+ */
+class Addon
+{
+    /**
+     * @var string
+     */
+    protected $identifier = '';
+
+    /**
+     * @var array
+     */
+    protected $modes = [];
+
+    /**
+     * @var array
+     */
+    protected $options = [];
+
+    /**
+     * @var array
+     */
+    protected $cssFiles = [];
+
+    /**
+     * @param string $identifier
+     */
+    public function __construct(string $identifier)
+    {
+        $this->identifier = $identifier;
+    }
+
+    /**
+     * @return string
+     */
+    public function getIdentifier(): string
+    {
+        return $this->identifier;
+    }
+
+    /**
+     * @param array $modes
+     * @return self
+     */
+    public function setModes(array $modes): Addon
+    {
+        $this->modes = $modes;
+
+        return $this;
+    }
+
+    /**
+     * @return array
+     */
+    public function getModes(): array
+    {
+        return $this->modes;
+    }
+
+    /**
+     * @param array $options
+     * @return self
+     */
+    public function setOptions(array $options): Addon
+    {
+        $this->options = $options;
+
+        return $this;
+    }
+
+    /**
+     * @return array
+     */
+    public function getOptions(): array
+    {
+        return $this->options;
+    }
+
+    /**
+     * @param array $cssFiles
+     * @return self
+     */
+    public function setCssFiles(array $cssFiles): Addon
+    {
+        $this->cssFiles = $cssFiles;
+
+        return $this;
+    }
+
+    /**
+     * @return array
+     */
+    public function getCssFiles(): array
+    {
+        return $this->cssFiles;
+    }
+}
diff --git a/typo3/sysext/t3editor/Classes/Exception/InvalidModeException.php b/typo3/sysext/t3editor/Classes/Exception/InvalidModeException.php
new file mode 100644 (file)
index 0000000..22c0f11
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\T3editor\Exception;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Exception;
+
+/**
+ * Exception thrown for invalid modes
+ */
+class InvalidModeException extends Exception
+{
+}
index b0db16c..943e4dd 100644 (file)
@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 namespace TYPO3\CMS\T3editor\Form\Element;
 
 /*
@@ -15,12 +16,14 @@ namespace TYPO3\CMS\T3editor\Form\Element;
  */
 
 use TYPO3\CMS\Backend\Form\Element\AbstractFormElement;
-use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
-use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
+use TYPO3\CMS\T3editor\Exception\InvalidModeException;
+use TYPO3\CMS\T3editor\Mode;
+use TYPO3\CMS\T3editor\Registry\AddonRegistry;
+use TYPO3\CMS\T3editor\Registry\ModeRegistry;
 use TYPO3\CMS\T3editor\T3editor;
 
 /**
@@ -28,29 +31,6 @@ use TYPO3\CMS\T3editor\T3editor;
  */
 class T3editorElement extends AbstractFormElement
 {
-    const MODE_CSS = 'css';
-    const MODE_HTML = 'html';
-    const MODE_JAVASCRIPT = 'javascript';
-    const MODE_MIXED = 'mixed';
-    const MODE_PHP = 'php';
-    const MODE_SPARQL = 'sparql';
-    const MODE_TYPOSCRIPT = 'typoscript';
-    const MODE_XML = 'xml';
-
-    /**
-     * @var array
-     */
-    protected $allowedModes = [
-        self::MODE_CSS,
-        self::MODE_HTML,
-        self::MODE_JAVASCRIPT,
-        self::MODE_MIXED,
-        self::MODE_PHP,
-        self::MODE_SPARQL,
-        self::MODE_TYPOSCRIPT,
-        self::MODE_XML,
-    ];
-
     /**
      * @var array
      */
@@ -62,13 +42,6 @@ class T3editorElement extends AbstractFormElement
     protected $mode = '';
 
     /**
-     * Counts the editors on the current page
-     *
-     * @var int
-     */
-    protected $editorCounter = 0;
-
-    /**
      * Relative path to EXT:t3editor
      *
      * @var string
@@ -76,18 +49,6 @@ class T3editorElement extends AbstractFormElement
     protected $extPath = '';
 
     /**
-     * @var string
-     */
-    protected $codemirrorPath = 'Resources/Public/JavaScript/Contrib/codemirror/js/';
-
-    /**
-     * RequireJS modules loaded for code completion
-     *
-     * @var array
-     */
-    protected $codeCompletionComponents = ['TsRef', 'CompletionResult', 'TsParser', 'TsCodeCompletion'];
-
-    /**
      * Default field wizards enabled for this element.
      *
      * @var array
@@ -99,7 +60,7 @@ class T3editorElement extends AbstractFormElement
         'otherLanguageContent' => [
             'renderType' => 'otherLanguageContent',
             'after' => [
-                'localizationStateSelector'
+                'localizationStateSelector',
             ],
         ],
         'defaultLanguageDifferences' => [
@@ -114,19 +75,35 @@ class T3editorElement extends AbstractFormElement
      * Render t3editor element
      *
      * @return array As defined in initializeResultArray() of AbstractNode
+     * @throws \TYPO3\CMS\T3editor\Exception\InvalidModeException
+     * @throws \InvalidArgumentException
+     * @throws \BadFunctionCallException
      */
-    public function render()
+    public function render(): array
     {
-        $this->getLanguageService()->includeLLFile('EXT:t3editor/Resources/Private/Language/locallang.xlf');
         $this->extPath = PathUtility::getAbsoluteWebPath(ExtensionManagementUtility::extPath('t3editor'));
-        $this->codemirrorPath = $this->extPath . $this->codemirrorPath;
+        $codeMirrorPath = $this->extPath . 'Resources/Public/JavaScript/Contrib/cm';
 
         $this->resultArray = $this->initializeResultArray();
+        $this->resultArray['stylesheetFiles'][] = $codeMirrorPath . '/lib/codemirror.css';
+        $this->resultArray['stylesheetFiles'][] = $this->extPath . '/Resources/Public/Css/t3editor.css';
+        $this->resultArray['requireJsModules'][] = [
+            'TYPO3/CMS/T3editor/T3editor' => 'function(T3editor) {T3editor.findAndInitializeEditors()}'
+        ];
+
+        // Compile and register t3editor configuration
+        GeneralUtility::makeInstance(T3editor::class)->registerConfiguration();
+
+        $registeredAddons = AddonRegistry::getInstance()->getForMode($this->getMode()->getFormatCode());
+        foreach ($registeredAddons as $addon) {
+            foreach ($addon->getCssFiles() as $cssFile) {
+                $this->resultArray['stylesheetFiles'][] = $cssFile;
+            }
+        }
 
         $parameterArray = $this->data['parameterArray'];
 
         $rows = MathUtility::forceIntegerInRange($parameterArray['fieldConf']['config']['rows'] ?: 10, 1, 40);
-        $this->setMode(isset($parameterArray['fieldConf']['config']['format']) ? $parameterArray['fieldConf']['config']['format'] : T3editor::MODE_MIXED);
 
         $attributes = [];
         $attributes['rows'] = $rows;
@@ -136,7 +113,7 @@ class T3editorElement extends AbstractFormElement
 
         $attributeString = '';
         foreach ($attributes as $param => $value) {
-            $attributeString .= $param . '="' . htmlspecialchars($value) . '" ';
+            $attributeString .= $param . '="' . htmlspecialchars((string)$value) . '" ';
         }
 
         $editorHtml = $this->getHTMLCodeForEditor(
@@ -182,50 +159,10 @@ class T3editorElement extends AbstractFormElement
 
         $this->resultArray['html'] = implode(LF, $html);
 
-        $this->resultArray['additionalJavaScriptPost'][] = 'require(["TYPO3/CMS/T3editor/T3editor"], function(T3editor) {T3editor.findAndInitializeEditors();});';
-
-        $this->initJavascriptCode();
         return $this->resultArray;
     }
 
     /**
-     * Sets the type of code to edit, use one of the predefined constants
-     *
-     * @param string $mode Expects one of the predefined constants
-     * @throws \InvalidArgumentException
-     */
-    public function setMode($mode)
-    {
-        if (!in_array($mode, $this->allowedModes, true)) {
-            throw new \InvalidArgumentException($mode . 'is not allowed', 1438352574);
-        }
-        $this->mode = $mode;
-    }
-
-    /**
-     * Get mode
-     *
-     * @return string
-     */
-    public function getMode()
-    {
-        return $this->mode;
-    }
-
-    /**
-     * Init the JavaScript code (header part) for editor
-     */
-    protected function initJavascriptCode()
-    {
-        $this->resultArray['stylesheetFiles'][] = 'EXT:t3editor/Resources/Public/Css/t3editor.css';
-        if ($this->mode === self::MODE_TYPOSCRIPT) {
-            foreach ($this->codeCompletionComponents as $codeCompletionComponent) {
-                $this->resultArray['requireJsModules'][] = 'TYPO3/CMS/T3editor/Plugins/CodeCompletion/' . $codeCompletionComponent;
-            }
-        }
-    }
-
-    /**
      * Generates HTML with code editor
      *
      * @param string $name Name attribute of HTML tag
@@ -234,136 +171,70 @@ class T3editorElement extends AbstractFormElement
      * @param string $additionalParams Any additional editor parameters
      * @param string $alt Alt attribute
      * @param array $hiddenfields
+     *
      * @return string Generated HTML code for editor
-     */
-    protected function getHTMLCodeForEditor($name, $class = '', $content = '', $additionalParams = '', $alt = '', array $hiddenfields = [])
-    {
+     * @throws \TYPO3\CMS\T3editor\Exception\InvalidModeException
+     */
+    protected function getHTMLCodeForEditor(
+        string $name,
+        string $class = '',
+        string $content = '',
+        string $additionalParams = '',
+        string $alt = '',
+        array $hiddenfields = []
+    ): string {
         $code = [];
         $attributes = [];
+        $mode = $this->getMode();
+        $registeredAddons = AddonRegistry::getInstance()->getForMode($mode->getFormatCode());
+
         $attributes['class'] = $class . ' t3editor';
         $attributes['alt'] = $alt;
-        $attributes['id'] = 't3editor_' . $this->editorCounter;
+        $attributes['id'] = 't3editor_' . md5($name);
         $attributes['name'] = $name;
-        $attributes['data-labels'] = json_encode($this->getLanguageService()->getLabelsWithPrefix('js.', 'label_'));
-        $attributes['data-instance-number'] =  $this->editorCounter;
-        $attributes['data-editor-path'] =  $this->extPath;
-        $attributes['data-codemirror-path'] =  $this->codemirrorPath;
-        $attributes['data-ajaxsavetype'] = ''; // no ajax save in FormEngine at the moment
-        $attributes['data-parserfile'] = $this->getParserfileByMode($this->mode);
-        $attributes['data-stylesheet'] = $this->getStylesheetByMode($this->mode);
+
+        $settings = AddonRegistry::getInstance()->compileSettings($registeredAddons);
+        $addons = [];
+        foreach ($registeredAddons as $addon) {
+            $addons[] = $addon->getIdentifier();
+        }
+
+        $attributes['data-codemirror-config'] = json_encode([
+            'mode' => $mode->getIdentifier(),
+            'addons' => json_encode($addons),
+            'options' => json_encode($settings)
+        ]);
 
         $attributesString = '';
         foreach ($attributes as $attribute => $value) {
-            $attributesString .= $attribute . '="' . htmlspecialchars($value) . '" ';
+            $attributesString .= $attribute . '="' . htmlspecialchars((string)$value) . '" ';
         }
         $attributesString .= $additionalParams;
 
-        $code[] = '<div class="t3editor">';
-        $code[] =   '<div class="t3e_wrap">';
-        $code[] =       str_replace([CR, LF], '', file_get_contents(GeneralUtility::getFileAbsFileName('EXT:t3editor/Resources/Private/Templates/t3editor.html')));
-        $code[] =   '</div>';
-        $code[] =   '<textarea ' . $attributesString . '>' . htmlspecialchars($content) . '</textarea>';
-        $code[] = '</div>';
+        $code[] = '<textarea ' . $attributesString . '>' . htmlspecialchars($content) . '</textarea>';
 
         if (!empty($hiddenfields)) {
-            foreach ($hiddenfields as $name => $value) {
-                $code[] = '<input type="hidden" name="' . htmlspecialchars($name) . '" value="' . htmlspecialchars($value) . '" />';
+            foreach ($hiddenfields as $attributeName => $value) {
+                $code[] = '<input type="hidden" name="' . htmlspecialchars($attributeName) . '" value="' . htmlspecialchars((string)$value) . '" />';
             }
         }
-        $this->editorCounter++;
         return implode(LF, $code);
     }
 
     /**
-     * Determine the correct parser js file for given mode
-     *
-     * @param string $mode
-     * @return string Parser file name
+     * @return Mode
+     * @throws InvalidModeException
      */
-    protected function getParserfileByMode($mode)
+    protected function getMode(): Mode
     {
-        $parserfile = [];
-        switch ($mode) {
-            case self::MODE_TYPOSCRIPT:
-                $relPath = '../../../parse_typoscript/';
-                $parserfile = [$relPath . 'tokenizetyposcript.js', $relPath . 'parsetyposcript.js'];
-                break;
-            case self::MODE_JAVASCRIPT:
-                $parserfile = ['tokenizejavascript.js', 'parsejavascript.js'];
-                break;
-            case self::MODE_CSS:
-                $parserfile = ['parsecss.js'];
-                break;
-            case self::MODE_XML:
-                $parserfile = ['parsexml.js'];
-                break;
-            case self::MODE_SPARQL:
-                $parserfile = ['parsesparql.js'];
-                break;
-            case self::MODE_HTML:
-                $parserfile = ['tokenizejavascript.js', 'parsejavascript.js', 'parsecss.js', 'parsexml.js', 'parsehtmlmixed.js'];
-                break;
-            case self::MODE_PHP:
-            case self::MODE_MIXED:
-                $parserfile = ['tokenizejavascript.js', 'parsejavascript.js', 'parsecss.js', 'parsexml.js', '../contrib/php/js/tokenizephp.js', '../contrib/php/js/parsephp.js', '../contrib/php/js/parsephphtmlmixed.js'];
-                break;
-        }
-        return json_encode($parserfile);
-    }
+        $config = $this->data['parameterArray']['fieldConf']['config'];
 
-    /**
-     * Determine the correct css file for given mode
-     *
-     * @param string $mode
-     * @return string css file name
-     */
-    protected function getStylesheetByMode($mode)
-    {
-        switch ($mode) {
-            case self::MODE_TYPOSCRIPT:
-                $stylesheet = [$this->extPath . 'Resources/Public/Css/t3editor_typoscript_colors.css'];
-                break;
-            case self::MODE_JAVASCRIPT:
-                $stylesheet = [$this->codemirrorPath . '../css/jscolors.css'];
-                break;
-            case self::MODE_CSS:
-                $stylesheet = [$this->codemirrorPath . '../css/csscolors.css'];
-                break;
-            case self::MODE_XML:
-                $stylesheet = [$this->codemirrorPath . '../css/xmlcolors.css'];
-                break;
-            case self::MODE_HTML:
-                $stylesheet = [$this->codemirrorPath . '../css/xmlcolors.css', $this->codemirrorPath . '../css/jscolors.css', $this->codemirrorPath . '../css/csscolors.css'];
-                break;
-            case self::MODE_SPARQL:
-                $stylesheet = [$this->codemirrorPath . '../css/sparqlcolors.css'];
-                break;
-            case self::MODE_PHP:
-                $stylesheet = [$this->codemirrorPath . '../contrib/php/css/phpcolors.css'];
-                break;
-            case self::MODE_MIXED:
-                $stylesheet = [$this->codemirrorPath . '../css/xmlcolors.css', $this->codemirrorPath . '../css/jscolors.css', $this->codemirrorPath . '../css/csscolors.css', $this->codemirrorPath . '../contrib/php/css/phpcolors.css'];
-                break;
-            default:
-                $stylesheet = [];
+        $identifier = $config['format'];
+        if (strpos($config['format'], '/') !== false) {
+            $parts = explode('/', $config['format']);
+            $identifier = end($parts);
         }
-        $stylesheet[] = $this->extPath . 'Resources/Public/Css/t3editor_inner.css';
-        return json_encode($stylesheet);
-    }
 
-    /**
-     * @return LanguageService
-     */
-    protected function getLanguageService()
-    {
-        return $GLOBALS['LANG'];
-    }
-
-    /**
-     * @return BackendUserAuthentication
-     */
-    protected function getBackendUserAuthentication()
-    {
-        return $GLOBALS['BE_USER'];
+        return ModeRegistry::getInstance()->getByFormatCode($identifier);
     }
 }
index 5640373..43cc979 100644 (file)
@@ -17,7 +17,10 @@ namespace TYPO3\CMS\T3editor\Hook;
 
 use TYPO3\CMS\Backend\Controller\File\EditFileController;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
-use TYPO3\CMS\T3editor\Form\Element\T3editorElement;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\T3editor\Exception\InvalidModeException;
+use TYPO3\CMS\T3editor\Registry\ModeRegistry;
+use TYPO3\CMS\T3editor\T3editor;
 
 /**
  * File edit hook for t3editor
@@ -25,55 +28,33 @@ use TYPO3\CMS\T3editor\Form\Element\T3editorElement;
 class FileEditHook
 {
     /**
-     * Editor mode to file extension mapping. This is just temporarily in place and will be removed after refactoring
-     * EXT:t3editor.
-     *
-     * @var array
-     */
-    protected $fileExtensions = [
-        T3editorElement::MODE_CSS => ['css'],
-        T3editorElement::MODE_HTML => ['htm', 'html'],
-        T3editorElement::MODE_JAVASCRIPT => ['js'],
-        T3editorElement::MODE_PHP => ['php', 'php5', 'php7', 'phps'],
-        T3editorElement::MODE_SPARQL => ['rq'],
-        T3editorElement::MODE_TYPOSCRIPT => ['ts', 'typoscript', 'txt'],
-        T3editorElement::MODE_XML => ['xml'],
-    ];
-
-    /**
      * Hook-function: inject t3editor JavaScript code before the page is compiled
      * called in file_edit module
      *
      * @param array $parameters
      * @param EditFileController $pObj
+     *
+     * @throws \InvalidArgumentException
      */
     public function preOutputProcessingHook(array $parameters, EditFileController $pObj)
     {
+        // Compile and register t3editor configuration
+        GeneralUtility::makeInstance(T3editor::class)->registerConfiguration();
+
         $target = '';
         if (isset($parameters['target']) && is_string($parameters['target'])) {
             $target = $parameters['target'];
         }
-        $parameters['dataColumnDefinition']['config']['renderType'] = 't3editor';
-        $parameters['dataColumnDefinition']['config']['format'] = $this->determineFormatByExtension($target);
-    }
-
-    /**
-     * @param string $fileIdentifier
-     * @return string
-     */
-    protected function determineFormatByExtension(string $fileIdentifier): string
-    {
-        $fileExtension = ResourceFactory::getInstance()->retrieveFileOrFolderObject($fileIdentifier)->getExtension();
-        if (empty($fileExtension)) {
-            return T3editorElement::MODE_MIXED;
-        }
 
-        foreach ($this->fileExtensions as $format => $extensions) {
-            if (in_array($fileExtension, $extensions, true)) {
-                return $format;
-            }
+        $fileExtension = ResourceFactory::getInstance()->retrieveFileOrFolderObject($target)->getExtension();
+        $modeRegistry = GeneralUtility::makeInstance(ModeRegistry::class);
+        try {
+            $mode = $modeRegistry->getByFileExtension($fileExtension);
+        } catch (InvalidModeException $e) {
+            $mode = $modeRegistry->getDefaultMode();
         }
 
-        return T3editorElement::MODE_MIXED;
+        $parameters['dataColumnDefinition']['config']['renderType'] = 't3editor';
+        $parameters['dataColumnDefinition']['config']['format'] = $mode->getFormatCode();
     }
 }
diff --git a/typo3/sysext/t3editor/Classes/Mode.php b/typo3/sysext/t3editor/Classes/Mode.php
new file mode 100644 (file)
index 0000000..6cdb41c
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\T3editor;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Represents a mode for CodeMirror
+ */
+class Mode
+{
+    /**
+     * @var string
+     */
+    protected $identifier = '';
+
+    /**
+     * @var string
+     */
+    protected $formatCode = '';
+
+    /**
+     * @var array
+     */
+    protected $fileExtensions = [];
+
+    /**
+     * @var bool
+     */
+    protected $isDefault = false;
+
+    /**
+     * @param string $identifier
+     */
+    public function __construct(string $identifier)
+    {
+        $this->identifier = $identifier;
+    }
+
+    /**
+     * @return string
+     */
+    public function getIdentifier(): string
+    {
+        return $this->identifier;
+    }
+
+    /**
+     * @return string
+     */
+    public function getFormatCode(): string
+    {
+        return $this->formatCode;
+    }
+
+    /**
+     * @param string $formatCode
+     * @return Mode
+     */
+    public function setFormatCode(string $formatCode): Mode
+    {
+        $this->formatCode = $formatCode;
+
+        return $this;
+    }
+
+    /**
+     * @param array $fileExtensions
+     * @return self
+     */
+    public function bindToFileExtensions(array $fileExtensions): Mode
+    {
+        $this->fileExtensions = $fileExtensions;
+
+        return $this;
+    }
+
+    /**
+     * @return array
+     */
+    public function getBoundFileExtensions(): array
+    {
+        return $this->fileExtensions;
+    }
+
+    /**
+     * @return Mode
+     */
+    public function setAsDefault(): Mode
+    {
+        $this->isDefault = true;
+
+        return $this;
+    }
+
+    /**
+     * @return bool
+     */
+    public function isDefault(): bool
+    {
+        return $this->isDefault;
+    }
+}
diff --git a/typo3/sysext/t3editor/Classes/Registry/AddonRegistry.php b/typo3/sysext/t3editor/Classes/Registry/AddonRegistry.php
new file mode 100644 (file)
index 0000000..75783a9
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\T3editor\Registry;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\SingletonInterface;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\T3editor\Addon;
+
+/**
+ * Registers and holds t3editor modes
+ */
+class AddonRegistry implements SingletonInterface
+{
+    /**
+     * @var Addon[]
+     */
+    protected $registeredAddons = [];
+
+    /**
+     * @return self
+     * @throws \InvalidArgumentException
+     */
+    public static function getInstance(): AddonRegistry
+    {
+        return GeneralUtility::makeInstance(static::class);
+    }
+
+    /**
+     * Registers addons for global use in t3editor
+     *
+     * @param Addon $addon
+     * @return self
+     */
+    public function register(Addon $addon): AddonRegistry
+    {
+        $this->registeredAddons[$addon->getIdentifier()] = $addon;
+
+        return $this;
+    }
+
+    /**
+     * @param string $mode
+     * @return Addon[]
+     */
+    public function getForMode(string $mode = ''): array
+    {
+        $addons = [];
+
+        foreach ($this->registeredAddons as $addon) {
+            if (empty($addon->getModes()) || in_array($mode, $addon->getModes(), true)) {
+                $addons[] = $addon;
+            }
+        }
+
+        return $addons;
+    }
+
+    /**
+     * @param Addon[] $addons
+     * @return array
+     */
+    public function compileSettings(array $addons): array
+    {
+        $settings = [];
+        foreach ($addons as $addon) {
+            $settings = array_merge($settings, $addon->getOptions());
+        }
+
+        return $settings;
+    }
+}
diff --git a/typo3/sysext/t3editor/Classes/Registry/ModeRegistry.php b/typo3/sysext/t3editor/Classes/Registry/ModeRegistry.php
new file mode 100644 (file)
index 0000000..746992a
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+declare(strict_types=1);
+namespace TYPO3\CMS\T3editor\Registry;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\SingletonInterface;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\T3editor\Exception\InvalidModeException;
+use TYPO3\CMS\T3editor\Mode;
+
+/**
+ * Registers and holds t3editor modes
+ */
+class ModeRegistry implements SingletonInterface
+{
+    /**
+     * @var Mode[]
+     */
+    protected $registeredModes = [];
+
+    /**
+     * @var Mode
+     */
+    protected $defaultMode;
+
+    /**
+     * @return self
+     * @throws \InvalidArgumentException
+     */
+    public static function getInstance(): ModeRegistry
+    {
+        return GeneralUtility::makeInstance(static::class);
+    }
+
+    /**
+     * Registers modes for t3editor
+     *
+     * @param Mode $mode
+     * @return self
+     */
+    public function register(Mode $mode): ModeRegistry
+    {
+        $this->registeredModes[$mode->getIdentifier()] = $mode;
+        if ($mode->isDefault()) {
+            $this->defaultMode = $mode;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Removes registered modes
+     *
+     * @param string $identifier
+     * @return self
+     */
+    public function unregister(string $identifier): ModeRegistry
+    {
+        if (isset($this->registeredModes[$identifier])) {
+            unset($this->registeredModes[$identifier]);
+        }
+
+        return $this;
+    }
+
+    /**
+     * @param string $identifier
+     * @return bool
+     */
+    public function isRegistered(string $identifier): bool
+    {
+        return isset($this->registeredModes[$identifier]);
+    }
+
+    /**
+     * @param string $identifier
+     * @return Mode
+     * @throws InvalidModeException
+     */
+    public function getByIdentifier(string $identifier): Mode
+    {
+        if ($this->isRegistered($identifier)) {
+            return $this->registeredModes[$identifier];
+        }
+
+        throw new InvalidModeException('Tried to get unregistered t3editor mode "' . $identifier . '"', 1499710202);
+    }
+
+    /**
+     * @param string $formatCode
+     * @return Mode
+     * @throws InvalidModeException
+     */
+    public function getByFormatCode(string $formatCode): Mode
+    {
+        foreach ($this->registeredModes as $mode) {
+            if ($mode->getFormatCode() === $formatCode) {
+                return $mode;
+            }
+        }
+
+        throw new InvalidModeException('Tried to get unregistered t3editor mode by format code "' . $formatCode . '"', 1499710203);
+    }
+
+    /**
+     * @param string $fileExtension
+     * @return Mode
+     * @throws InvalidModeException
+     */
+    public function getByFileExtension(string $fileExtension): Mode
+    {
+        foreach ($this->registeredModes as $mode) {
+            if (in_array($fileExtension, $mode->getBoundFileExtensions(), true)) {
+                return $mode;
+            }
+        }
+
+        throw new InvalidModeException('Cannot find a registered mode for requested file extension "' . $fileExtension . '"', 1500306488);
+    }
+
+    /**
+     * @return Mode
+     */
+    public function getDefaultMode(): Mode
+    {
+        return $this->defaultMode;
+    }
+}
index 4507970..a1eca4c 100644 (file)
@@ -1,4 +1,5 @@
 <?php
+declare(strict_types=1);
 namespace TYPO3\CMS\T3editor;
 
 /*
@@ -14,388 +15,140 @@ namespace TYPO3\CMS\T3editor;
  * The TYPO3 project - inspiring people to share!
  */
 
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
-use TYPO3\CMS\Core\Http\Response;
-use TYPO3\CMS\Core\Page\PageRenderer;
-use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
+use TYPO3\CMS\Core\Cache\CacheManager;
+use TYPO3\CMS\Core\Cache\Frontend\PhpFrontend;
+use TYPO3\CMS\Core\Package\PackageManager;
+use TYPO3\CMS\Core\SingletonInterface;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Core\Utility\PathUtility;
+use TYPO3\CMS\T3editor\Registry\AddonRegistry;
+use TYPO3\CMS\T3editor\Registry\ModeRegistry;
 
 /**
- * Provides a javascript-driven code editor with syntax highlighting for TS, HTML, CSS and more
+ * Provides necessary code to setup a t3editor instance in FormEngine
  */
-class T3editor implements \TYPO3\CMS\Core\SingletonInterface
+class T3editor implements SingletonInterface
 {
-    const MODE_TYPOSCRIPT = 'typoscript';
-    const MODE_JAVASCRIPT = 'javascript';
-    const MODE_CSS = 'css';
-    const MODE_XML = 'xml';
-    const MODE_HTML = 'html';
-    const MODE_PHP = 'php';
-    const MODE_SPARQL = 'sparql';
-    const MODE_MIXED = 'mixed';
-
-    /**
-     * @var string
-     */
-    protected $mode = '';
-
-    /**
-     * @var string
-     */
-    protected $ajaxSaveType = '';
-
-    /**
-     * Counts the editors on the current page
-     *
-     * @var int
-     */
-    protected $editorCounter = 0;
-
     /**
-     * Path to EXT:t3editor
-     *
-     * @var string
-     */
-    protected $extPath = '';
-
-    /**
-     * Relative directory to codemirror
-     *
-     * @var string
-     */
-    protected $codemirrorPath = 'Resources/Public/JavaScript/Contrib/codemirror/js/';
-
-    /**
-     * RequireJS modules loaded for code completion
-     *
      * @var array
      */
-    protected $codeCompletionComponents = ['TsRef', 'CompletionResult', 'TsParser', 'TsCodeCompletion'];
+    protected $configuration;
 
     /**
-     * sets the type of code to edit (::MODE_TYPOSCRIPT, ::MODE_JAVASCRIPT)
+     * Registers the configuration and bootstraps the modes / addons.
      *
-     * @param $mode    string Expects one of the predefined constants
-     * @return \TYPO3\CMS\T3editor\T3editor
+     * @throws \InvalidArgumentException
      */
-    public function setMode($mode)
+    public function registerConfiguration()
     {
-        $this->mode = $mode;
-        return $this;
-    }
+        $configuration = $this->buildConfiguration();
 
-    /**
-     * Set the AJAX save type
-     *
-     * @param string $ajaxSaveType
-     * @return \TYPO3\CMS\T3editor\T3editor
-     */
-    public function setAjaxSaveType($ajaxSaveType)
-    {
-        $this->ajaxSaveType = $ajaxSaveType;
-        return $this;
-    }
+        if (isset($configuration['modes'])) {
+            $modeRegistry = ModeRegistry::getInstance();
+            foreach ($configuration['modes'] as $formatCode => $mode) {
+                $modeInstance = GeneralUtility::makeInstance(Mode::class, $mode['module'])->setFormatCode($formatCode);
 
-    /**
-     * Set mode by file
-     *
-     * @param string $file
-     */
-    public function setModeByFile($file)
-    {
-        $fileInfo = GeneralUtility::split_fileref($file);
-        $this->setModeByType($fileInfo['fileext']);
-    }
+                if (!empty($mode['extensions']) && is_array($mode['extensions'])) {
+                    $modeInstance->bindToFileExtensions($mode['extensions']);
+                }
 
-    /**
-     * Set mode by type
-     *
-     * @param string $type
-     */
-    public function setModeByType($type)
-    {
-        switch ($type) {
-            case 'html':
-            case 'htm':
-            case 'tmpl':
-                $mode = self::MODE_HTML;
-                break;
-            case 'js':
-                $mode = self::MODE_JAVASCRIPT;
-                break;
-            case 'xml':
-            case 'svg':
-                $mode = self::MODE_XML;
-                break;
-            case 'css':
-                $mode = self::MODE_CSS;
-                break;
-            case 'ts':
-            case 'typoscript':
-                $mode = self::MODE_TYPOSCRIPT;
-                break;
-            case 'sparql':
-                $mode = self::MODE_SPARQL;
-                break;
-            case 'php':
-            case 'phpsh':
-            case 'inc':
-                $mode = self::MODE_PHP;
-                break;
-            default:
-                $mode = self::MODE_MIXED;
-        }
-        $this->setMode($mode);
-    }
+                if (isset($mode['default']) && $mode['default'] === true) {
+                    $modeInstance->setAsDefault();
+                }
 
-    /**
-     * Get mode
-     *
-     * @return string
-     */
-    public function getMode()
-    {
-        return $this->mode;
-    }
+                $modeRegistry->register($modeInstance);
+            }
+        }
 
-    /**
-     * Creates a new instance of the class
-     */
-    public function __construct()
-    {
-        $GLOBALS['LANG']->includeLLFile('EXT:t3editor/Resources/Private/Language/locallang.xlf');
-        // Disable pmktextarea to avoid conflicts (thanks Peter Klein for this suggestion)
-        $GLOBALS['BE_USER']->uc['disablePMKTextarea'] = 1;
+        $addonRegistry = GeneralUtility::makeInstance(AddonRegistry::class);
+        if (isset($configuration['addons'])) {
+            foreach ($configuration['addons'] as $addon) {
+                $addonInstance = GeneralUtility::makeInstance(Addon::class, $addon['module']);
 
-        $this->extPath = PathUtility::getAbsoluteWebPath(ExtensionManagementUtility::extPath('t3editor'));
-        $this->codemirrorPath = $this->extPath . $this->codemirrorPath;
-    }
+                if (!empty($addon['cssFiles']) && is_array($addon['cssFiles'])) {
+                    $addonInstance->setCssFiles($addon['cssFiles']);
+                }
 
-    /**
-     * Retrieves JavaScript code (header part) for editor
-     *
-     * @return string
-     */
-    public function getJavascriptCode()
-    {
-        /** @var $pageRenderer \TYPO3\CMS\Core\Page\PageRenderer */
-        $pageRenderer = $this->getPageRenderer();
-        $pageRenderer->addCssFile($this->extPath . 'Resources/Public/Css/t3editor.css');
-        // Include editor-js-lib
-        $pageRenderer->addJsLibrary('codemirror', $this->codemirrorPath . 'codemirror.js');
-        if ($this->mode === self::MODE_TYPOSCRIPT) {
-            foreach ($this->codeCompletionComponents as $codeCompletionComponent) {
-                $pageRenderer->loadRequireJsModule('TYPO3/CMS/T3editor/Plugins/CodeCompletion/' . $codeCompletionComponent);
-            }
-        }
-        $pageRenderer->loadRequireJsModule('TYPO3/CMS/T3editor/T3editor');
-        return '';
-    }
+                if (!empty($addon['options']) && is_array($addon['options'])) {
+                    $addonInstance->setOptions($addon['options']);
+                }
 
-    /**
-     * Get the template code, prepared for javascript (no line breaks, quoted in single quotes)
-     *
-     * @return string The template code, prepared to use in javascript
-     */
-    protected function getPreparedTemplate()
-    {
-        $T3editor_template = file_get_contents(
-            GeneralUtility::getFileAbsFileName('EXT:t3editor/Resources/Private/Templates/t3editor.html')
-        );
-        return str_replace([CR, LF], '', $T3editor_template);
-    }
+                if (!empty($addon['modes']) && is_array($addon['modes'])) {
+                    $addonInstance->setModes($addon['modes']);
+                }
 
-    /**
-     * Determine the correct parser js file for given mode
-     *
-     * @param string $mode
-     * @return string Parser file name
-     */
-    protected function getParserfileByMode($mode)
-    {
-        switch ($mode) {
-            case self::MODE_TYPOSCRIPT:
-                $relPath = '../../../parse_typoscript/';
-                $parserfile = [$relPath . 'tokenizetyposcript.js', $relPath . 'parsetyposcript.js'];
-                break;
-            case self::MODE_JAVASCRIPT:
-                $parserfile = ['tokenizejavascript.js', 'parsejavascript.js'];
-                break;
-            case self::MODE_CSS:
-                $parserfile = ['parsecss.js'];
-                break;
-            case self::MODE_XML:
-                $parserfile = ['parsexml.js'];
-                break;
-            case self::MODE_SPARQL:
-                $parserfile = ['parsesparql.js'];
-                break;
-            case self::MODE_HTML:
-                $parserfile = ['tokenizejavascript.js', 'parsejavascript.js', 'parsecss.js', 'parsexml.js', 'parsehtmlmixed.js'];
-                break;
-            case self::MODE_PHP:
-            case self::MODE_MIXED:
-                $parserfile = ['tokenizejavascript.js', 'parsejavascript.js', 'parsecss.js', 'parsexml.js', '../contrib/php/js/tokenizephp.js', '../contrib/php/js/parsephp.js', '../contrib/php/js/parsephphtmlmixed.js'];
-                break;
-            default:
-                $parserfile = [];
+                $addonRegistry->register($addonInstance);
+            }
         }
-        return json_encode($parserfile);
     }
 
     /**
-     * Determine the correct css file for given mode
+     * Compiles the configuration for t3editor. Configuration is stored in caching framework.
      *
-     * @param string $mode
-     * @return string css file name
+     * @return array
+     * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
+     * @throws \TYPO3\CMS\Core\Cache\Exception\InvalidDataException
+     * @throws \InvalidArgumentException
      */
-    protected function getStylesheetByMode($mode)
+    protected function buildConfiguration(): array
     {
-        switch ($mode) {
-            case self::MODE_TYPOSCRIPT:
-                $stylesheet = [$this->extPath . 'Resources/Public/Css/t3editor_typoscript_colors.css'];
-                break;
-            case self::MODE_JAVASCRIPT:
-                $stylesheet = [$this->codemirrorPath . '../css/jscolors.css'];
-                break;
-            case self::MODE_CSS:
-                $stylesheet = [$this->codemirrorPath . '../css/csscolors.css'];
-                break;
-            case self::MODE_XML:
-                $stylesheet = [$this->codemirrorPath . '../css/xmlcolors.css'];
-                break;
-            case self::MODE_HTML:
-                $stylesheet = [$this->codemirrorPath . '../css/xmlcolors.css', $this->codemirrorPath . '../css/jscolors.css', $this->codemirrorPath . '../css/csscolors.css'];
-                break;
-            case self::MODE_SPARQL:
-                $stylesheet = [$this->codemirrorPath . '../css/sparqlcolors.css'];
-                break;
-            case self::MODE_PHP:
-                $stylesheet = [$this->codemirrorPath . '../contrib/php/css/phpcolors.css'];
-                break;
-            case self::MODE_MIXED:
-                $stylesheet = [$this->codemirrorPath . '../css/xmlcolors.css', $this->codemirrorPath . '../css/jscolors.css', $this->codemirrorPath . '../css/csscolors.css', $this->codemirrorPath . '../contrib/php/css/phpcolors.css'];
-                break;
-            default:
-                $stylesheet = [];
+        if ($this->configuration !== null) {
+            return $this->configuration;
         }
-        $stylesheet[] = $this->extPath . 'Resources/Public/Css/t3editor_inner.css';
-        return json_encode($stylesheet);
-    }
 
-    /**
-     * Generates HTML with code editor
-     *
-     * @param string $name Name attribute of HTML tag
-     * @param string $class Class attribute of HTML tag
-     * @param string $content Content of the editor
-     * @param string $additionalParams Any additional editor parameters
-     * @param string $alt Alt attribute
-     * @param array $hiddenfields
-     * @return string Generated HTML code for editor
-     */
-    public function getCodeEditor($name, $class = '', $content = '', $additionalParams = '', $alt = '', array $hiddenfields = [])
-    {
-        $code = '';
-        $class .= ' t3editor';
-        $alt = trim($alt);
-        $code .=
-            '<div class="t3editor">'
-                . '<div class="t3e_wrap">'
-                    . $this->getPreparedTemplate()
-                . '</div>'
-                . '<textarea '
-                    . 'id="t3editor_' . (int)$this->editorCounter . '" '
-                    . 'name="' . htmlspecialchars($name) . '" '
-                    . 'class="' . htmlspecialchars($class) . '" '
-                    . $additionalParams . ' '
-                    . ($alt !== '' ? ' alt="' . htmlspecialchars($alt) . '"' : '')
-                    . ' data-labels="' . htmlspecialchars(json_encode($GLOBALS['LANG']->getLabelsWithPrefix('js.', 'label_'))) . '"'
-                    . ' data-instance-number="' . (int)$this->editorCounter . '"'
-                    . ' data-editor-path="' . htmlspecialchars($this->extPath) . '"'
-                    . ' data-codemirror-path="' . htmlspecialchars($this->codemirrorPath) . '"'
-                    . ' data-ajaxsavetype="' . htmlspecialchars($this->ajaxSaveType) . '"'
-                    . ' data-parserfile="' . htmlspecialchars($this->getParserfileByMode($this->mode)) . '"'
-                    . ' data-stylesheet="' . htmlspecialchars($this->getStylesheetByMode($this->mode)) . '"'
-                    . '>' . htmlspecialchars($content)
-                . '</textarea>'
-            . '</div>';
-        if (!empty($hiddenfields)) {
-            foreach ($hiddenfields as $name => $value) {
-                $code .= '<input type="hidden" ' . 'name="' . htmlspecialchars($name) . '" ' . 'value="' . htmlspecialchars($value) . '" />';
-            }
-        }
-        $this->editorCounter++;
-        return $code;
-    }
+        $this->configuration = [
+            'modes' => [],
+            'addons' => [],
+        ];
+
+        $cache = $this->getCache();
+        $cacheIdentifier = $this->generateCacheIdentifier('T3editorConfiguration');
+        $configurationFromCache = $cache->requireOnce($cacheIdentifier);
+        if ($configurationFromCache !== false) {
+            $this->configuration = $configurationFromCache;
+        } else {
+            $packageManager = GeneralUtility::makeInstance(PackageManager::class);
+            $packages = $packageManager->getActivePackages();
+
+            foreach ($packages as $package) {
+                $configurationPath = $package->getPackagePath() . 'Configuration/Backend/T3editor';
+                $modesFileNameForPackage = $configurationPath . '/Modes.php';
+                if (is_file($modesFileNameForPackage)) {
+                    $definedModes = require_once($modesFileNameForPackage);
+                    if (is_array($definedModes)) {
+                        $this->configuration['modes'] = array_merge($this->configuration['modes'], $definedModes);
+                    }
+                }
 
-    /**
-     * Save the content from t3editor retrieved via Ajax
-     *
-     * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
-     * @return ResponseInterface
-     */
-    public function ajaxSaveCode(ServerRequestInterface $request, ResponseInterface $response)
-    {
-        // cancel if its not an Ajax request
-        if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX) {
-            $codeType = isset($request->getParsedBody()['t3editor_savetype']) ? $request->getParsedBody()['t3editor_savetype'] : $request->getQueryParams()['t3editor_savetype'];
-            $savingsuccess = false;
-            try {
-                if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3editor/classes/class.tx_t3editor.php']['ajaxSaveCode'])) {
-                    $_params = [
-                        'pObj' => &$this,
-                        'type' => $codeType,
-                        'request' => $request,
-                        'response' => $response
-                    ];
-                    foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3editor/classes/class.tx_t3editor.php']['ajaxSaveCode'] as $key => $_funcRef) {
-                        $savingsuccess = GeneralUtility::callUserFunction($_funcRef, $_params, $this) || $savingsuccess;
+                $addonsFileNameForPackage = $configurationPath . '/Addons.php';
+                if (is_file($addonsFileNameForPackage)) {
+                    $definedAddons = require_once($addonsFileNameForPackage);
+                    if (is_array($definedAddons)) {
+                        $this->configuration['addons'] = array_merge($this->configuration['addons'], $definedAddons);
                     }
                 }
-                $responseContent = ['result' => $savingsuccess];
-            } catch (\Exception $e) {
-                $responseContent = [
-                    'result' => false,
-                    'exceptionMessage' => htmlspecialchars($e->getMessage()),
-                    'exceptionCode' => $e->getCode()
-                ];
             }
-            /** @var Response $response */
-            $response = GeneralUtility::makeInstance(Response::class);
-            $response->getBody()->write(json_encode($responseContent));
+            $cache->set($cacheIdentifier, 'return json_decode(\'' . json_encode($this->configuration) . '\', true);');
         }
 
-        return $response;
+        return $this->configuration;
     }
 
     /**
-     * Gets plugins that are defined at $TYPO3_CONF_VARS['EXTCONF']['t3editor']['plugins']
-     * Called by AjaxRequestHandler
-     *
-     * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
-     * @return ResponseInterface
+     * @param string $key
+     * @return string
      */
-    public function getPlugins(ServerRequestInterface $request, ResponseInterface $response)
+    protected function generateCacheIdentifier(string $key): string
     {
-        $result = [];
-        $plugins = &$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3editor']['plugins'];
-        if (is_array($plugins)) {
-            $result = array_values($plugins);
-        }
-        $response->getBody()->write(json_encode($result));
-        return $response;
+        return $key . '_' . sha1(TYPO3_version . PATH_site . $key);
     }
 
     /**
-     * @return PageRenderer
+     * @return PhpFrontend
+     * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException
+     * @throws \InvalidArgumentException
      */
-    protected function getPageRenderer()
+    protected function getCache(): PhpFrontend
     {
-        return GeneralUtility::makeInstance(PageRenderer::class);
+        return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_core');
     }
 }
index d76a318..8dd0a86 100644 (file)
@@ -45,25 +45,9 @@ class TypoScriptReferenceLoader
      */
     public function processAjaxRequest(ServerRequestInterface $request, ResponseInterface $response)
     {
-        $parsedBody = $request->getParsedBody();
-        $queryParams = $request->getQueryParams();
-
         // Load the TSref XML information:
-        $this->loadFile(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('t3editor') . 'Resources/Private/tsref.xml');
-        $fetch = isset($parsedBody['fetch']) ? $parsedBody['fetch'] : $queryParams['fetch'];
-        $content = null;
-
-        switch ($fetch) {
-            case 'types':
-                $response->getBody()->write(json_encode($this->getTypes()));
-                break;
-            case 'description':
-                $typeId = isset($parsedBody['typeId']) ? $parsedBody['typeId'] : $queryParams['typeId'];
-                $parameterName = isset($parsedBody['parameterName']) ? $parsedBody['parameterName'] : $queryParams['parameterName'];
-                $response = $this->getDescription($typeId, $parameterName);
-                $response->withHeader('Content-Type', 'text/html; charset=utf8');
-                break;
-        }
+        $this->loadFile(GeneralUtility::getFileAbsFileName('EXT:t3editor/Resources/Private/tsref.xml'));
+        $response->getBody()->write(json_encode($this->getTypes()));
         return $response;
     }
 
@@ -75,7 +59,7 @@ class TypoScriptReferenceLoader
     protected function loadFile($filepath)
     {
         // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
-        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
+        $previousValueOfEntityLoader = libxml_disable_entity_loader();
         $this->xmlDoc = new \DOMDocument('1.0', 'utf-8');
         $this->xmlDoc->loadXML(file_get_contents($filepath));
         libxml_disable_entity_loader($previousValueOfEntityLoader);
@@ -88,7 +72,7 @@ class TypoScriptReferenceLoader
      *
      * @return array
      */
-    protected function getTypes()
+    protected function getTypes() : array
     {
         $types = $this->xmlDoc->getElementsByTagName('type');
         $typeArr = [];
@@ -115,58 +99,4 @@ class TypoScriptReferenceLoader
         }
         return $typeArr;
     }
-
-    /**
-     * Get description
-     *
-     * @param string $typeId
-     * @param string $parameterName
-     * @return ResponseInterface
-     */
-    protected function getDescription($typeId, $parameterName = '')
-    {
-        /** @var \TYPO3\CMS\Core\Http\Response $response */
-        $response = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Http\Response::class);
-        if (!$typeId) {
-            $response->getBody()->write($GLOBALS['LANG']->getLL('typeIDMissing'));
-            $response = $response->withStatus(500);
-            return $response;
-        }
-        // getElementById does only work with schema
-        $type = $this->getType($typeId);
-        // Retrieve propertyDescription
-        if ($parameterName) {
-            $properties = $type->getElementsByTagName('property');
-            foreach ($properties as $propery) {
-                $propName = $propery->getAttribute('name');
-                if ($propName == $parameterName) {
-                    $descriptions = $propery->getElementsByTagName('description');
-                    if ($descriptions->length) {
-                        $description = $descriptions->item(0)->textContent;
-                        $description = htmlspecialchars($description);
-                        $description = nl2br($description);
-                        $response->getBody()->write($description);
-                        break;
-                    }
-                }
-            }
-        }
-        return $response;
-    }
-
-    /**
-     * Get type
-     *
-     * @param string $typeId
-     * @return \DOMNode
-     */
-    protected function getType($typeId)
-    {
-        $types = $this->xmlDoc->getElementsByTagName('type');
-        foreach ($types as $type) {
-            if ($type->getAttribute('id') == $typeId) {
-                return $type;
-            }
-        }
-    }
 }
index 4cf5ede..8af7cb2 100644 (file)
@@ -4,18 +4,6 @@
  * Definitions for routes provided by EXT:t3editor
  */
 return [
-    // Save the TypoScript
-    't3editor_save' => [
-        'path' => '/t3editor/save',
-        'target' => \TYPO3\CMS\T3editor\T3editor::class . '::ajaxSaveCode'
-    ],
-
-    // Get plugins
-    't3editor_get_plugins' => [
-        'path' => '/t3editor/get-plugins',
-        'target' => \TYPO3\CMS\T3editor\T3editor::class . '::getPlugins'
-    ],
-
     // Get TSRef
     't3editor_tsref' => [
         'path' => '/t3editor/tsref',
diff --git a/typo3/sysext/t3editor/Configuration/Backend/T3editor/Addons.php b/typo3/sysext/t3editor/Configuration/Backend/T3editor/Addons.php
new file mode 100644 (file)
index 0000000..bc38fc6
--- /dev/null
@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * Addons for t3editor
+ */
+return [
+    'dialog/dialog' => [
+        'module' => 'cm/addon/dialog/dialog',
+        'cssFiles' => [
+            'EXT:t3editor/Resources/Public/JavaScript/Contrib/cm/addon/dialog/dialog.css',
+        ],
+    ],
+    'display/fullscreen' => [
+        'module' => 'cm/addon/display/fullscreen',
+        'cssFiles' => [
+            'EXT:t3editor/Resources/Public/JavaScript/Contrib/cm/addon/display/fullscreen.css',
+        ],
+    ],
+    'display/autorefresh' => [
+        'module' => 'cm/addon/display/autorefresh',
+    ],
+    'display/panel' => [
+        'module' => 'cm/addon/display/panel',
+    ],
+    'fold/xml-fold' => [
+        'module' => 'cm/addon/fold/xml-fold',
+    ],
+    'scroll/simplescrollbars' => [
+        'module' => 'cm/addon/scroll/simplescrollbars',
+        'cssFiles' => [
+            'EXT:t3editor/Resources/Public/JavaScript/Contrib/cm/addon/scroll/simplescrollbars.css',
+        ],
+        'options' => [
+            'scrollbarStyle' => 'simple',
+        ],
+    ],
+    'scroll/annotatescrollbar' => [
+        'module' => 'cm/addon/scroll/annotatescrollbar',
+    ],
+    'search/searchcursor' => [
+        'module' => 'cm/addon/search/searchcursor',
+    ],
+    'search/search' => [
+        'module' => 'cm/addon/search/search',
+    ],
+    'search/jump-to-line' => [
+        'module' => 'cm/addon/search/jump-to-line',
+    ],
+    'search/matchesonscrollbar' => [
+        'module' => 'cm/addon/search/matchesonscrollbar',
+        'cssFiles' => [
+            'EXT:t3editor/Resources/Public/JavaScript/Contrib/cm/addon/search/matchesonscrollbar.css',
+        ],
+    ],
+    'edit/matchbrackets' => [
+        'module' => 'cm/addon/edit/matchbrackets',
+        'options' => [
+            'matchBrackets' => true,
+        ],
+    ],
+    'edit/closebrackets' => [
+        'module' => 'cm/addon/edit/closebrackets',
+        'options' => [
+            'autoCloseBrackets' => true,
+        ],
+    ],
+    'selection/active-line' => [
+        'module' => 'cm/addon/selection/active-line',
+        'options' => [
+            'styleActiveLine' => true,
+        ],
+    ],
+    'edit/matchtags' => [
+        'module' => 'cm/addon/edit/matchtags',
+        'options' => [
+            'matchTags' => true,
+        ],
+    ],
+    'edit/closetag' => [
+        'module' => 'cm/addon/edit/closetag',
+        'options' => [
+            'autoCloseTags' => true,
+        ],
+    ],
+    'hint/show-hint' => [
+        'module' => 'cm/addon/hint/show-hint',
+        'cssFiles' => [
+            'EXT:t3editor/Resources/Public/JavaScript/Contrib/cm/addon/hint/show-hint.css',
+        ],
+        'options' => [
+            'hintOptions' => [
+                'completeSingle' => false,
+            ],
+        ],
+    ],
+    'hint/css-hint' => [
+        'module' => 'cm/addon/hint/css-hint',
+        'modes' => ['css'],
+    ],
+    'hint/xml-hint' => [
+        'module' => 'cm/addon/hint/xml-hint',
+        'modes' => ['htmlmixed', 'xml'],
+    ],
+    'hint/html-hint' => [
+        'module' => 'cm/addon/hint/html-hint',
+        'modes' => ['htmlmixed'],
+    ],
+    'hint/javascript-hint' => [
+        'module' => 'cm/addon/hint/javascript-hint',
+        'modes' => ['javascript'],
+    ],
+    'hint/sql-hint' => [
+        'module' => 'cm/addon/hint/sql-hint',
+        'modes' => ['sql'],
+    ],
+    'hint/typoscript-hint' => [
+        'module' => 'TYPO3/CMS/T3editor/Addon/Hint/TypoScriptHint',
+        'modes' => ['typoscript'],
+    ],
+];
diff --git a/typo3/sysext/t3editor/Configuration/Backend/T3editor/Modes.php b/typo3/sysext/t3editor/Configuration/Backend/T3editor/Modes.php
new file mode 100644 (file)
index 0000000..29c1bc8
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * Mode definitions for t3editor
+ */
+return [
+    'css' => [
+        'module' => 'cm/mode/css/css',
+        'extensions' => ['css'],
+    ],
+    'html' => [
+        'module' => 'cm/mode/htmlmixed/htmlmixed',
+        'extensions' => ['htm', 'html'],
+        'default' => true,
+    ],
+    'javascript' => [
+        'module' => 'cm/mode/javascript/javascript',
+        'extensions' => ['javascript'],
+    ],
+    'php' => [
+        'module' => 'cm/mode/php/php',
+        'extensions' => ['php', 'php5', 'php7', 'phps'],
+    ],
+    'typoscript' => [
+        'module' => 'TYPO3/CMS/T3editor/Mode/typoscript/typoscript',
+        'extensions' => ['ts', 'typoscript', 'tsconfig'],
+    ],
+    'xml' => [
+        'module' => 'cm/mode/xml/xml',
+        'extensions' => ['xml']
+    ]
+];
diff --git a/typo3/sysext/t3editor/Resources/Private/Templates/t3editor.html b/typo3/sysext/t3editor/Resources/Private/Templates/t3editor.html
deleted file mode 100644 (file)
index c2e35ce..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<div class="t3e_modalOverlay"><i class="fa fa-spinner fa-spin"></i></div>
-<div class="t3e_iframe_wrap"></div>
-<div class="t3e_statusbar_wrap">
-       <span class="t3e_statusbar_title"></span>
-       <span class="t3e_statusbar_status"></span>
-</div>
diff --git a/typo3/sysext/t3editor/Resources/Private/TypeScript/T3editor.ts b/typo3/sysext/t3editor/Resources/Private/TypeScript/T3editor.ts
new file mode 100644 (file)
index 0000000..b04d4cb
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+import CodeMirror = require('cm/lib/codemirror');
+import $ = require('jquery');
+
+/**
+ * Module: TYPO3/CMS/T3editor/T3editor
+ * Renders CodeMirror into FormEngine
+ * @exports TYPO3/CMS/T3editor/T3editor
+ */
+class T3editor {
+
+  /**
+   * @param {string} position
+   * @param {string} label
+   * @returns {HTMLElement}
+   */
+  public static createPanelNode(position: string, label: string): HTMLElement {
+    const $panelNode = $('<div />', {
+      class: 'CodeMirror-panel CodeMirror-panel-' + position,
+      id: 'panel-' + position,
+    }).append(
+      $('<span />').text(label),
+    );
+
+    return $panelNode.get(0);
+  }
+
+  /**
+   * The constructor, set the class properties default values
+   */
+  constructor() {
+    this.initialize();
+  }
+
+  /**
+   * Initializes CodeMirror on available texteditors
+   */
+  public findAndInitializeEditors(): void {
+    $(document).find('textarea.t3editor').each(function(this: Element) {
+      const $textarea = $(this);
+
+      if (!$textarea.prop('is_t3editor')) {
+        const config = $textarea.data('codemirror-config');
+        const modeParts = config.mode.split('/');
+        const addons = $.merge([modeParts.join('/')], JSON.parse(config.addons));
+        const options = JSON.parse(config.options);
+
+        // Load mode + registered addons
+        require(addons, (): void => {
+          const cm = CodeMirror.fromTextArea($textarea.get(0), {
+            extraKeys: {
+              'Ctrl-Alt-F': (codemirror: any): void => {
+                codemirror.setOption('fullScreen', !codemirror.getOption('fullScreen'));
+              },
+              'Ctrl-Space': 'autocomplete',
+              'Esc': (codemirror: any): void => {
+                if (codemirror.getOption('fullScreen')) {
+                  codemirror.setOption('fullScreen', false);
+                }
+              },
+            },
+            fullScreen: false,
+            lineNumbers: true,
+            lineWrapping: true,
+            mode: modeParts[modeParts.length - 1],
+          });
+
+          // Set options
+          $.each(options, (key: string, value: any): void => {
+            cm.setOption(key, value);
+          });
+
+          cm.addPanel(
+            T3editor.createPanelNode('bottom', $textarea.attr('alt')),
+            {
+              position: 'bottom',
+              stable: true,
+            },
+          );
+        });
+
+        $textarea.prop('is_t3editor', true);
+      }
+    });
+  }
+
+  /**
+   * Initialize the events
+   */
+  public initialize(): void {
+    $((): void => {
+      this.findAndInitializeEditors();
+    });
+  }
+}
+
+// Create an instance and return it
+export = new T3editor();
index f158ab0..366db35 100644 (file)
@@ -10,4 +10,4 @@
  * 
  * The TYPO3 project - inspiring people to share!
  */
-.t3e_codeCompleteBox,.t3e_descriptionBox,.t3e_toolbar_icon,.t3e_wrap{border:1px solid #b9b9b9}.CodeMirror-wrapping{position:relative;min-width:100%}.CodeMirror-wrapping div{line-height:13px!important}div.CodeMirror-line-numbers{margin-right:2px;padding-right:3px;padding-left:3px;font-size:10px;text-align:right;line-height:13px!important}.TSREF_description_label,.TSREF_type_label{font-weight:700}#TSREF_description{margin-bottom:5px}.t3e_codeCompleteBox{padding:0;background-color:#f4f4f4}.t3e_codeCompleteBox ul{margin:0;padding:0;list-style-type:none}.t3e_codeCompleteBox ul li{padding-left:2px;padding-right:2px;cursor:pointer}.t3e_codeCompleteBox ul li.active{padding-left:2px;padding-right:2px;background-color:#fff}.t3e_descriptionBox,.t3e_modalOverlay,.t3e_wrap{background-color:#f4f4f4}.t3e_codeCompleteBox ul li span.word_definedTSREFProperty,.t3e_codeCompleteBox ul li span.word_undefined,.t3e_codeCompleteBox ul li span.word_undefinedTSREFProperty{font-family:monospace}.t3e_codeCompleteBox ul li span.word_definedTSREFProperty,.t3e_codeCompleteBox ul li span.word_undefined{color:#dd123d}.t3e_codeCompleteBox ul li span.word_undefinedTSREFProperty{color:#0080ff}.t3e_codeCompleteBox ul li span.word_userProperty{font-size:12px;color:#737373}.t3e_descriptionBox{position:absolute;top:0;left:0;z-index:190;padding:2px 5px;height:220px;width:260px}.t3e_toolbar{position:absolute;top:0;right:50px;width:200px}.t3e_toolbar_icon{float:left;width:20px;height:20px}.t3e_codeCompleteWrap{position:absolute;top:0;left:0;z-index:190}.t3e_wrap{position:relative;min-width:100%}.t3e_modalOverlay{position:absolute;top:0;left:0;z-index:200;width:100%;height:100%;text-align:center}.t3e_fullscreen{position:absolute;top:0;left:0;z-index:999}.t3e_iframe_wrap{margin:0 0 0 3px}.t3e_iframe{display:block;padding:0}.t3e_toolbar_wrap{clear:both;padding-right:20px;width:100%;font-size:11px}.t3e_statusbar_wrap{position:absolute;left:0;bottom:0;padding:2px 5px;height:20px;width:100%;font-size:11px;background-color:#8c8c8c}.t3e_footeritem_active,.t3e_statusbar_overlay,.t3e_statusbar_overlay ul li:hover{background-color:#f4f4f4}.t3e_statusbar_wrap span{margin:3px;color:#fff}.t3e_statusbar_item{float:right;height:16px;border-left:1px solid gray;padding:4px 14px 0}.t3e_clickable{cursor:hand}.t3e_statusbar_overlay{position:absolute;bottom:20px;right:17px;z-index:100;opacity:.85;border-left:1px solid gray;border-right:1px solid gray;border-top:1px solid gray;padding:5px 0 10px;width:180px;height:70%}.t3e_statusbar_overlay#t3e_statusbar_overlay_options{height:8em}.t3e_statusbar_overlay ul{margin:0;padding:0;list-style-type:none}.t3e_statusbar_overlay ul li{cursor:hand;padding:2px 6px;color:#000}.t3e_statusbar_overlay ul li label{cursor:pointer}#t3e_modalOverlay_help{top:10%;left:5%;height:80%;width:90%;border:1px solid #737373;padding:10px;background-image:none}
\ No newline at end of file
+.CodeMirror-fullscreen{top:64px}.CodeMirror-panel{background:#f7f7f7;padding:3px 6px;font-size:.85em}.CodeMirror-panel-bottom{border-top:1px solid #ddd}div.CodeMirror span.CodeMirror-matchingbracket{color:#6ca52b}
\ No newline at end of file
diff --git a/typo3/sysext/t3editor/Resources/Public/Css/t3editor_inner.css b/typo3/sysext/t3editor/Resources/Public/Css/t3editor_inner.css
deleted file mode 100644 (file)
index 40a92c2..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*!
- * This file is part of the TYPO3 CMS project.
- * 
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- * 
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- * 
- * The TYPO3 project - inspiring people to share!
- */
-.editbox{border-width:0;margin:1px 0 0 .3em;padding:0;font-family:monospace;font-size:12px;color:#000;line-height:13px;white-space:nowrap;background-color:#fff}
\ No newline at end of file
diff --git a/typo3/sysext/t3editor/Resources/Public/Css/t3editor_typoscript_colors.css b/typo3/sysext/t3editor/Resources/Public/Css/t3editor_typoscript_colors.css
deleted file mode 100644 (file)
index a7d1c42..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*!
- * This file is part of the TYPO3 CMS project.
- * 
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- * 
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- * 
- * The TYPO3 project - inspiring people to share!
- */
-.ts-condition,.ts-error,.ts-operator{font-weight:700}.other{color:#000}.ts-value{color:#dd123d}.keyword,.keyword2,.keyword3,.reserved,.ts-objstr,.ts-operator{color:#0080ff}.ts-value_copy{color:#006400}.ts-default,.ts-ignored,.ts-value_unset{background-color:#5abc55}.ts-comment{font-style:italic;color:#737373}.ts-condition{color:#fff;background-color:maroon}.ts-error{border:1px dashed #dd123d;background-color:#ffc800}.highlight-bracket{color:#fff;background-color:#5abc55}.error-bracket{color:#fff;background-color:#dd123d}.editbox,pre.code{color:#737373}
\ No newline at end of file
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/CompletionResult.js b/typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/CompletionResult.js
new file mode 100644 (file)
index 0000000..d3a550c
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/T3editor/Addon/Hint/CompletionResult
+ * Contains the CompletionResult class
+ */
+define(['jquery'], function ($) {
+       /**
+        *
+        * @type {{tsRef: null, tsTreeNode: null}}
+        * @exports TYPO3/CMS/T3editor/Addon/Hint/CompletionResult
+        */
+       var CompletionResult = {
+               tsRef: null,
+               tsTreeNode: null
+       };
+
+       /**
+        *
+        * @param {Object} config
+        * @returns {{tsRef: null, tsTreeNode: null}}
+        */
+       CompletionResult.init = function(config) {
+               CompletionResult.tsRef = config.tsRef;
+               CompletionResult.tsTreeNode = config.tsTreeNode;
+
+               return CompletionResult;
+       };
+
+       /**
+        * returns the type of the currentTsTreeNode
+        *
+        * @returns {*}
+        */
+       CompletionResult.getType = function() {
+               var val = CompletionResult.tsTreeNode.getValue();
+               if (CompletionResult.tsRef.isType(val)) {
+                       return CompletionResult.tsRef.getType(val);
+               }
+               return null;
+       };
+
+       /**
+        * returns a list of possible path completions (proposals), which is:
+        * a list of the children of the current TsTreeNode (= userdefined properties)
+        * and a list of properties allowed for the current object in the TsRef
+        * remove all words from list that don't start with the string in filter
+        *
+        * @param {String} filter beginning of the words contained in the proposal list
+        * @return {Array} an Array of Proposals
+        */
+       CompletionResult.getFilteredProposals = function(filter) {
+               var defined = [],
+                       propArr = [],
+                       childNodes = CompletionResult.tsTreeNode.getChildNodes(),
+                       value = CompletionResult.tsTreeNode.getValue();
+
+               // first get the childNodes of the Node (=properties defined by the user)
+               for (var key in childNodes) {
+                       if (typeof childNodes[key].value !== 'undefined' && childNodes[key].value !== null) {
+                               var propObj = {};
+                               propObj.word = key;
+                               if (CompletionResult.tsRef.typeHasProperty(value, childNodes[key].name)) {
+                                       CompletionResult.tsRef.cssClass = 'definedTSREFProperty';
+                                       propObj.type = childNodes[key].value;
+                               } else {
+                                       propObj.cssClass = 'userProperty';
+                                       if (CompletionResult.tsRef.isType(childNodes[key].value)) {
+                                               propObj.type = childNodes[key].value;
+                                       } else {
+                                               propObj.type = '';
+                                       }
+                               }
+                               propArr.push(propObj);
+                               defined[key] = true;
+                       }
+               }
+
+               // then get the tsref properties
+               var props = CompletionResult.tsRef.getPropertiesFromTypeId(CompletionResult.tsTreeNode.getValue());
+               for (var key in props) {
+                       // show just the TSREF properties - no properties of the array-prototype and no properties which have been defined by the user
+                       if (typeof props[key].value !== 'undefined' && defined[key] !== true) {
+                               var propObj = {};
+                               propObj.word = key;
+                               propObj.cssClass = 'undefinedTSREFProperty';
+                               propObj.type = props[key].value;
+                               propArr.push(propObj);
+                       }
+               }
+
+               var result = [],
+                       wordBeginning = '';
+
+               for (var i = 0; i < propArr.length; i++) {
+                       if (filter.length === 0) {
+                               result.push(propArr[i]);
+                               continue;
+                       }
+                       wordBeginning = propArr[i].word.substring(0, filter.length);
+                       if (wordBeginning.toLowerCase() === filter.toLowerCase()) {
+                               result.push(propArr[i]);
+                       }
+               }
+               return result;
+       };
+
+       return CompletionResult;
+});
\ No newline at end of file
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/TsCodeCompletion.js b/typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/TsCodeCompletion.js
new file mode 100644 (file)
index 0000000..4246713
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/T3editor/Addon/Hint/TsCodeCompletion
+ * Contains the TsCodeCompletion class
+ */
+define([
+       'jquery',
+       'TYPO3/CMS/T3editor/Addon/Hint/TsRef',
+       'TYPO3/CMS/T3editor/Addon/Hint/TsParser',
+       'TYPO3/CMS/T3editor/Addon/Hint/CompletionResult'
+], function ($, TsRef, TsParser, CompletionResult) {
+       /**
+        *
+        * @type {{tsRef: *, proposals: null, compResult: null, currentCursorPosition: null, extTsObjTree: {}, codemirror: null, parser: null, plugins: string[]}}
+        * @exports TYPO3/CMS/T3editor/CodeCompletion/TsCodeCompletion
+        */
+       var TsCodeCompletion = {
+               tsRef: TsRef,
+               proposals: null,
+               compResult: null,
+               currentCursorPosition: null,
+               extTsObjTree: {},
+               codemirror: null,
+               parser: null
+       };
+
+       /**
+        * All external templates along the rootline have to be loaded,
+        * this function retrieves the JSON code by committing a AJAX request
+        */
+       TsCodeCompletion.loadExtTemplatesAsync = function() {
+               var id = TsCodeCompletion.getGetVar('id');
+               if (id === '') {
+                       return;
+               }
+               $.ajax({
+                       url: TYPO3.settings.ajaxUrls['t3editor_codecompletion_loadtemplates'],
+                       data: {
+                               pageId: id
+                       },
+                       success: function(response) {
+                               TsCodeCompletion.extTsObjTree.c = response;
+                               TsCodeCompletion.resolveExtReferencesRec(TsCodeCompletion.extTsObjTree.c);
+                       }
+               });
+       };
+
+       /**
+        * Get the value of a given GET parameter
+        *
+        * @param {String} name
+        * @return {String}
+        */
+       TsCodeCompletion.getGetVar = function(name) {
+               var get_string = document.location.search,
+                       return_value = '',
+                       value;
+
+               do { //This loop is made to catch all instances of any get variable.
+                       var name_index = get_string.indexOf(name + '=');
+                       if (name_index !== -1) {
+                               get_string = get_string.substr(name_index + name.length + 1, get_string.length - name_index);
+                               var end_of_value = get_string.indexOf('&');
+                               if (end_of_value !== -1) {
+                                       value = get_string.substr(0, end_of_value);
+                               } else {
+                                       value = get_string;
+                               }
+
+                               if (return_value === '' || value === '') {
+                                       return_value += value;
+                               } else {
+                                       return_value += ', ' + value;
+                               }
+                       }
+               } while (name_index !== -1);
+
+               // Restores all the blank spaces.
+               var space = return_value.indexOf('+');
+               while (space !== -1) {
+                       return_value = return_value.substr(0, space) + ' ' + return_value.substr(space + 1, return_value.length);
+                       space = return_value.indexOf('+');
+               }
+
+               return return_value;
+       };
+
+       /**
+        * Since the references are not resolved server side we have to do it client-side
+        * Benefit: less loading time due to less data which has to be transmitted
+        *
+        * @param {Array} childNodes
+        */
+       TsCodeCompletion.resolveExtReferencesRec = function(childNodes) {
+               for (var key in childNodes) {
+                       var childNode;
+                       // if the childnode has a value and there is a part of a reference operator ('<')
+                       // and it does not look like a html tag ('>')
+                       if (childNodes[key].v && childNodes[key].v[0] === '<' && childNodes[key].v.indexOf('>') === -1 ) {
+                               var path = $.trim(childNodes[key].v.replace(/</, ''));
+                               // if there are still whitespaces it's no path
+                               if (path.indexOf(' ') === -1) {
+                                       childNode = TsCodeCompletion.getExtChildNode(path);
+                                       // if the node was found - reference it
+                                       if (childNode !== null) {
+                                               childNodes[key] = childNode;
+                                       }
+                               }
+                       }
+                       // if there was no reference-resolving then we go deeper into the tree
+                       if (!childNode && childNodes[key].c) {
+                               TsCodeCompletion.resolveExtReferencesRec(childNodes[key].c);
+                       }
+               }
+       };
+
+       /**
+        * Get the child node of given path
+        *
+        * @param {String} path
+        * @returns {Object}
+        */
+       TsCodeCompletion.getExtChildNode = function(path) {
+               var extTree = TsCodeCompletion.extTsObjTree,
+                       path = path.split('.'),
+                       pathSeg;
+
+               for (var i = 0; i < path.length; i++) {
+                       pathSeg = path[i];
+                       if (typeof extTree.c === 'undefined' || typeof extTree.c[pathSeg] === 'undefined') {
+                               return null;
+                       }
+                       extTree = extTree.c[pathSeg];
+               }
+               return extTree;
+       };
+
+       /**
+        *
+        * @returns {String}
+        */
+       TsCodeCompletion.getFilter = function() {
+               var currentLine = TsCodeCompletion.codemirror.getTokenAt(TsCodeCompletion.currentCursorPosition).string;
+               if (currentLine) {
+                       var filter = currentLine.replace('.', '');
+                       return filter.replace(/\s/g, '');
+               }
+               return '';
+       };
+
+       /**
+        * Refreshes the code completion list based on the cursor's position
+        */
+       TsCodeCompletion.refreshCodeCompletion = function(codemirror) {
+               TsCodeCompletion.codemirror = codemirror;
+
+               // retrieves the node right to the cursor
+               TsCodeCompletion.currentCursorPosition = TsCodeCompletion.codemirror.doc.getCursor();
+
+               // the cursornode has to be stored cause inserted breaks have to be deleted after pressing enter if the codecompletion is active
+               var filter = TsCodeCompletion.getFilter();
+
+               if (TsCodeCompletion.compResult === null || TsCodeCompletion.codemirror.getTokenAt(TsCodeCompletion.currentCursorPosition).string === '.') {
+                       // TODO: implement cases: operatorCompletion reference/copy path completion (formerly found in getCompletionResults())
+                       var currentTsTreeNode = TsCodeCompletion.parser.buildTsObjTree(TsCodeCompletion.codemirror);
+                       TsCodeCompletion.compResult = CompletionResult.init({
+                               tsRef: TsRef,
+                               tsTreeNode: currentTsTreeNode
+                       });
+               }
+
+               TsCodeCompletion.proposals = TsCodeCompletion.compResult.getFilteredProposals(filter);
+
+               var proposals = [];
+               for (var i = 0; i < TsCodeCompletion.proposals.length; i++) {
+                       proposals[i] = TsCodeCompletion.proposals[i].word;
+               }
+
+               return proposals;
+       };
+
+       /**
+        * Resets the completion list
+        */
+       TsCodeCompletion.resetCompList = function() {
+               TsCodeCompletion.compResult = null;
+       };
+
+       $(function() {
+               TsCodeCompletion.parser = TsParser.init(TsCodeCompletion.tsRef, TsCodeCompletion.extTsObjTree);
+               TsCodeCompletion.tsRef.loadTsrefAsync();
+               TsCodeCompletion.loadExtTemplatesAsync();
+       });
+
+       return TsCodeCompletion;
+});
\ No newline at end of file
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/TsParser.js b/typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/TsParser.js
new file mode 100644 (file)
index 0000000..1ba5181
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/T3editor/Addon/Hint/TsParser
+ * Contains the TsCodeCompletion class
+ */
+define([
+       'jquery', 'TYPO3/CMS/T3editor/Addon/Hint/TsRef'
+], function ($) {
+       /**
+        *
+        * @type {{typeId: null, properties: null, typeTree: Array, doc: null, tsRef: null, extTsObjTree: Array, tsTree: null}}
+        * @exports TYPO3/CMS/T3editor/Addon/Hint/TsParser
+        */
+       var TsParser = {
+               typeId: null,
+               properties: null,
+               typeTree: [],
+               doc: null,
+               tsRef: null,
+               extTsObjTree: [],
+               tsTree: null
+       };
+
+       /**
+        *
+        * @param {Object} tsRef
+        * @param {Object} extTsObjTree
+        * @returns {{typeId: null, properties: null, typeTree: Array, doc: null, tsRef: null, extTsObjTree: Array, tsTree: null}}
+        */
+       TsParser.init = function(tsRef, extTsObjTree) {
+               TsParser.tsRef = tsRef;
+               TsParser.extTsObjTree = extTsObjTree;
+               TsParser.tsTree = new TsParser.treeNode('_L_');
+
+               return TsParser;
+       };
+
+       /**
+        *
+        * @param {String} nodeName
+        */
+       TsParser.treeNode = function(nodeName) {
+               this.name = nodeName;
+               this.childNodes = [];
+               this.extPath = '';
+               this.value = '';
+               this.isExternal = false;
+
+               /**
+                * Returns local properties and the properties of the external templates
+                *
+                * @return {Array}
+                */
+               this.getChildNodes = function() {
+                       var node = this.getExtNode();
+                       if (node !== null && typeof node.c === 'object') {
+                               for (key in node.c) {
+                                       var tn = new TsParser.treeNode(key, this.tsObjTree);
+                                       tn.global = true;
+                                       tn.value = (node.c[key].v)? node.c[key].v : "";
+                                       tn.isExternal = true;
+                                       this.childNodes[key] = tn;
+                               }
+                       }
+                       return this.childNodes;
+               };
+
+               /**
+                * Returns the value of a node
+                *
+                * @returns {String}
+                */
+               this.getValue = function() {
+                       if (this.value) {
+                               return this.value;
+                       }
+                       var node = this.getExtNode();
+                       if (node && node.v) {
+                               return node.v;
+                       }
+
+                       var type = this.getNodeTypeFromTsref();
+                       if (type) {
+                               return type;
+                       }
+                       return '';
+               };
+
+               /**
+                * This method will try to resolve the properties recursively from right
+                * to left. If the node's value property is not set, it will look for the
+                * value of its parent node, and if there is a matching childProperty
+                * (according to the TSREF) it will return the childProperties value.
+                * If there is no value in the parent node it will go one step further
+                * and look into the parent node of the parent node,...
+                *
+                * @return {String}
+                */
+               this.getNodeTypeFromTsref = function() {
+                       var path = this.extPath.split('.'),
+                               lastSeg = path.pop();
+
+                       // attention: there will be recursive calls if necessary
+                       var parentValue = this.parent.getValue();
+                       if (parentValue) {
+                               if (TsParser.tsRef.typeHasProperty(parentValue, lastSeg)) {
+                                       var type = TsParser.tsRef.getType(parentValue);
+                                       return type.properties[lastSeg].value;
+                               }
+                       }
+                       return '';
+               };
+
+               /**
+                * Will look in the external ts-tree (static templates, templates on other pages)
+                * if there is a value or childproperties assigned to the current node.
+                * The method uses the extPath of the current node to navigate to the corresponding
+                * node in the external tree
+                *
+                * @return {Object}
+                */
+               this.getExtNode = function() {
+                       var extTree = TsParser.extTsObjTree,
+                               path,
+                               pathSeg;
+
+                       if (this.extPath === '') {
+                               return extTree;
+                       }
+                       path = this.extPath.split('.');
+
+                       for (var i = 0; i < path.length; i++) {
+                               pathSeg = path[i];
+                               if (typeof extTree.c === 'undefined' || typeof extTree.c[pathSeg] === 'undefined') {
+                                       return null;
+                               }
+                               extTree = extTree.c[pathSeg];
+                       }
+                       return extTree;
+               };
+       };
+
+       /**
+        * Check if there is an operator in the line and return it
+        * if there is none, return -1
+        *
+        * @return {(String|Number)}
+        */
+       TsParser.getOperator = function(line) {
+               var operators = [':=', '=<', '<', '>', '='];
+               for (var i = 0; i < operators.length; i++) {
+                       var op = operators[i];
+                       if (line.indexOf(op) !== -1) {
+                               // check if there is some HTML in this line (simple check, however it's the only difference between a reference operator and HTML)
+                               // we do this check only in case of the two operators "=<" and "<" since the delete operator would trigger our "HTML-finder"
+                               if ((op === '=<' || op === '<') && line.indexOf('>') > -1) {
+                                       // if there is a ">" in the line suppose there's some HTML
+                                       return '=';
+                               }
+                               return op;
+                       }
+               }
+               return -1;
+       };
+
+       /**
+        * Build the TypoScript object tree
+        */
+       TsParser.buildTsObjTree = function(codemirror) {
+               TsParser.tsTree = new TsParser.treeNode('');
+               TsParser.tsTree.value = 'TLO';
+
+               function Stack() {
+               }
+               Stack.prototype = [];
+               Stack.prototype.lastElementEquals = function(str) {
+                       return this.length > 0 && this[this.length-1] === str;
+               };
+
+               Stack.prototype.popIfLastElementEquals = function(str) {
+                       if (this.lastElementEquals(str)) {
+                               this.pop();
+                               return true;
+                       }
+                       return false;
+               };
+
+               var currentLine = 0,
+                       cursorPosition = codemirror.getCursor(),
+                       line = '',
+                       stack = new Stack(),
+                       prefixes = [],
+                       ignoreLine = false,
+                       insideCondition = false;
+
+               while (currentLine <= cursorPosition.line) {
+                       line = '';
+                       var tokens = codemirror.getLineTokens(currentLine);
+                       for (var i = 0; i <= tokens.length; ++i) {
+                               if (i < tokens.length && tokens[i].string.length > 0) {
+                                       var tokenValue = tokens[i].string;
+
+                                       if (tokenValue[0] === '#') {
+                                               stack.push('#');
+                                       } else if (tokenValue === '(') {
+                                               stack.push('(');
+                                       } else if (tokenValue[0] === '/' && tokenValue[1] === '*') {
+                                               stack.push('/*');
+                                       } else if (tokenValue === '{') {
+                                               // TODO: ignore whole block if wrong whitespaces in this line
+                                               if (TsParser.getOperator(line) === -1) {
+                                                       stack.push('{');
+                                                       prefixes.push($.trim(line));
+                                                       ignoreLine = true;
+                                               }
+                                       }
+                                       // TODO: conditions
+                                       // if condition starts -> ignore everything until end of condition
+                                       if (tokenValue.search(/^\s*\[.*\]/) !== -1
+                                               && line.search(/\S/) === -1
+                                               && tokenValue.search(/^\s*\[(global|end|GLOBAL|END)\]/) === -1
+                                               && !stack.lastElementEquals('#')
+                                               && !stack.lastElementEquals('/*')
+                                               && !stack.lastElementEquals('{')
+                                               && !stack.lastElementEquals('(')
+                                       ) {
+                                               insideCondition = true;
+                                               ignoreLine = true;
+                                       }
+
+                                       // if end of condition reached
+                                       if (line.search(/\S/) === -1
+                                               && !stack.lastElementEquals('#')
+                                               && !stack.lastElementEquals('/*')
+                                               && !stack.lastElementEquals('(')
+                                               && (
+                                                       (tokenValue.search(/^\s*\[(global|end|GLOBAL|END)\]/) !== -1
+                                                       && !stack.lastElementEquals('{'))
+                                                       || (tokenValue.search(/^\s*\[(global|GLOBAL)\]/) !== -1)
+                                               )
+                                       ) {
+                                               insideCondition = false;
+                                               ignoreLine = true;
+                                       }
+
+                                       if (tokenValue === ')') {
+                                               stack.popIfLastElementEquals('(');
+                                       }
+                                       if (tokenValue[0] === '*' && tokenValue[1] === '/') {
+                                               stack.popIfLastElementEquals('/*');
+                                               ignoreLine = true;
+                                       }
+                                       if (tokenValue === '}') {
+                                               //no characters except whitespace allowed before closing bracket
+                                               var trimmedLine = line.replace(/\s/g, '');
+                                               if (trimmedLine === '') {
+                                                       stack.popIfLastElementEquals('{');
+                                                       if (prefixes.length > 0) {
+                                                               prefixes.pop();
+                                                       }
+                                                       ignoreLine = true;
+                                               }
+                                       }
+                                       if (!stack.lastElementEquals('#')) {
+                                               line += tokenValue;
+                                       }
+                               } else {
+                                       // ignore comments, ...
+                                       if (!stack.lastElementEquals('/*') && !stack.lastElementEquals('(') && !ignoreLine && !insideCondition) {
+                                               line = $.trim(line);
+                                               // check if there is any operator in this line
+                                               var op = TsParser.getOperator(line);
+                                               if (op !== -1) {
+                                                       // figure out the position of the operator
+                                                       var pos = line.indexOf(op);
+                                                       // the target objectpath should be left to the operator
+                                                       var path = line.substring(0, pos);
+                                                       // if we are in between curly brackets: add prefixes to object path
+                                                       if (prefixes.length > 0) {
+                                                               path = prefixes.join('.') + '.' + path;
+                                                       }
+                                                       // the type or value should be right to the operator
+                                                       var str = line.substring(pos + op.length, line.length);
+                                                       path = $.trim(path);
+                                                       str = $.trim(str);
+                                                       switch (op) { // set a value or create a new object
+                                                               case '=':
+                                                                       //ignore if path is empty or contains whitespace
+                                                                       if (path.search(/\s/g) === -1 && path.length > 0) {
+                                                                               TsParser.setTreeNodeValue(path, str);
+                                                                       }
+                                                                       break;
+                                                               case '=<': // reference to another object in the tree
+                                                                       // resolve relative path
+                                                                       if (prefixes.length > 0 && str.substr(0, 1) === '.') {
+                                                                               str = prefixes.join('.') + str;
+                                                                       }
+                                                                       //ignore if either path or str is empty or contains whitespace
+                                                                       if (path.search(/\s/g) === -1
+                                                                               && path.length > 0
+                                                                               && str.search(/\s/g) === -1
+                                                                               && str.length > 0
+                                                                       ) {
+                                                                               TsParser.setReference(path, str);
+                                                                       }
+                                                                       break;
+                                                               case '<': // copy from another object in the tree
+                                                                       // resolve relative path
+                                                                       if (prefixes.length > 0 && str.substr(0, 1) === '.') {
+                                                                               str = prefixes.join('.') + str;
+                                                                       }
+                                                                       //ignore if either path or str is empty or contains whitespace
+                                                                       if (path.search(/\s/g) === -1
+                                                                               && path.length > 0
+                                                                               && str.search(/\s/g) === -1
+                                                                               && str.length > 0
+                                                                       ) {
+                                                                               TsParser.setCopy(path, str);
+                                                                       }
+                                                                       break;
+                                                               case '>': // delete object value and properties
+                                                                       TsParser.deleteTreeNodeValue(path);
+                                                                       break;
+                                                               case ':=': // function operator
+                                                                       // TODO: function-operator
+                                                                       break;
+                                                       }
+                                               }
+                                       }
+                                       stack.popIfLastElementEquals('#');
+                                       ignoreLine = false;
+                               }
+                       }
+                       currentLine++;
+               }
+               // when node at cursorPos is reached:
+               // save currentLine, currentTsTreeNode and filter if necessary
+               // if there is a reference or copy operator ('<' or '=<')
+               // return the treeNode of the path right to the operator,
+               // else try to build a path from the whole line
+               if (!stack.lastElementEquals('/*') && !stack.lastElementEquals('(') && !ignoreLine) {
+                       var i = line.indexOf('<');
+
+                       if (i !== -1) {
+                               var path = line.substring(i+1, line.length);
+                               path = $.trim(path);
+                               if (prefixes.length > 0 && path.substr(0, 1) === '.') {
+                                       path = prefixes.join('.') + path;
+                               }
+                       } else {
+                               var path = line;
+                               if (prefixes.length > 0) {
+                                       path = prefixes.join('.') + '.' + path;
+                                       path = path.replace(/\s/g, '');
+                               }
+                       }
+                       var lastDot = path.lastIndexOf('.');
+                       path = path.substring(0, lastDot);
+               }
+               return TsParser.getTreeNode(path);
+       };
+
+       /**
+        * Iterates through the object tree, and creates treenodes
+        * along the path, if necessary
+        *
+        * @param {String} path
+        * @returns {Object}
+        */
+       TsParser.getTreeNode = function(path) {
+               path = $.trim(path);
+               if (path.length === 0) {
+                       return TsParser.tsTree;
+               }
+               var aPath = path.split('.');
+
+               var subTree = TsParser.tsTree.childNodes,
+                       pathSeg,
+                       parent = TsParser.tsTree;
+
+               // step through the path from left to right
+               for (var i = 0; i < aPath.length; i++) {
+                       pathSeg = aPath[i];
+
+                       // if there isn't already a treenode
+                       if (typeof subTree[pathSeg] === 'undefined' || typeof subTree[pathSeg].childNodes === 'undefined') { // if this subpath is not defined in the code
+                               // create a new treenode
+                               subTree[pathSeg] = new TsParser.treeNode(pathSeg);
+                               subTree[pathSeg].parent = parent;
+                               // the extPath has to be set, so the TreeNode can retrieve the respecting node in the external templates
+                               var extPath = parent.extPath;
+                               if (extPath) {
+                                       extPath += '.';
+                               }
+                               extPath += pathSeg;
+                               subTree[pathSeg].extPath = extPath;
+                       }
+                       if (i === aPath.length - 1) {
+                               return subTree[pathSeg];
+                       }
+                       parent = subTree[pathSeg];
+                       subTree = subTree[pathSeg].childNodes;
+               }
+       };
+
+       /**
+        * Navigates to the respecting treenode,
+        * create nodes in the path, if necessary, and sets the value
+        *
+        * @param {String} path
+        * @param {String} value
+        */
+       TsParser.setTreeNodeValue = function(path, value) {
+               var treeNode = TsParser.getTreeNode(path);
+               // if we are inside a GIFBUILDER Object
+               if (treeNode.parent !== null && (treeNode.parent.value === "GIFBUILDER" || treeNode.parent.getValue() === "GMENU_itemState") && value === "TEXT") {
+                       value = 'GB_TEXT';
+               }
+               if (treeNode.parent !== null && (treeNode.parent.value === "GIFBUILDER" || treeNode.parent.getValue() === "GMENU_itemState") && value === "IMAGE") {
+                       value = 'GB_IMAGE';
+               }
+
+               // just override if it is a real objecttype
+               if (TsParser.tsRef.isType(value)) {
+                       treeNode.value = value;
+               }
+       };
+
+       /**
+        * Navigates to the respecting treenode,
+        * creates nodes if necessary, empties the value and childNodes-Array
+        *
+        * @param {String} path
+        */
+       TsParser.deleteTreeNodeValue = function(path) {
+               var treeNode = TsParser.getTreeNode(path);
+               // currently the node is not deleted really, it's just not displayed cause value == null
+               // deleting it would be a cleaner solution
+               treeNode.value = null;
+               treeNode.childNodes = {};
+       };
+
+       /**
+        * Copies a reference of the treeNode specified by path2
+        * to the location specified by path1
+        *
+        * @param {String} path1
+        * @param {String} path2
+        */
+       TsParser.setReference = function(path1, path2) {
+               var path1arr = path1.split('.'),
+                       lastNodeName = path1arr[path1arr.length - 1],
+                       treeNode1 = TsParser.getTreeNode(path1),
+                       treeNode2 = TsParser.getTreeNode(path2);
+
+               if (treeNode1.parent !== null) {
+                       treeNode1.parent.childNodes[lastNodeName] = treeNode2;
+               } else {
+                       TsParser.tsTree.childNodes[lastNodeName] = treeNode2;
+               }
+       };
+
+       /**
+        * copies a treeNode specified by path2
+        * to the location specified by path1
+        *
+        * @param {String} path1
+        * @param {String} path2
+        */
+       TsParser.setCopy = function(path1, path2) {
+               this.clone = function(myObj) {
+                       if (typeof myObj !== 'object') {
+                               return myObj;
+                       }
+
+                       var myNewObj = {};
+                       for (var i in myObj) {
+                               // disable recursive cloning for parent object -> copy by reference
+                               if (i !== 'parent') {
+                                       if (typeof myObj[i] === 'object') {
+                                               myNewObj[i] = this.clone(myObj[i]);
+                                       } else {
+                                               myNewObj[i] = myObj[i];
+                                       }
+                               } else {
+                                       myNewObj.parent = myObj.parent;
+                               }
+                       }
+                       return myNewObj;
+               };
+
+               var path1arr = path1.split('.'),
+                       lastNodeName = path1arr[path1arr.length - 1],
+                       treeNode1 = TsParser.getTreeNode(path1),
+                       treeNode2 = TsParser.getTreeNode(path2);
+
+               if (treeNode1.parent !== null) {
+                       treeNode1.parent.childNodes[lastNodeName] = this.clone(treeNode2);
+               } else {
+                       TsParser.tsTree.childNodes[lastNodeName] = this.clone(treeNode2);
+               }
+       };
+
+       return TsParser;
+});
\ No newline at end of file
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/TsRef.js b/typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/TsRef.js
new file mode 100644 (file)
index 0000000..7a0343b
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/T3editor/CodeCompletion/TsRef
+ * Contains the TsCodeCompletion class
+ */
+define(['jquery'], function ($) {
+       /**
+        *
+        * @type {{typeId: null, properties: null, typeTree: Array, doc: null}}
+        * @exports TYPO3/CMS/T3editor/CodeCompletion/TsRef
+        */
+       var TsRef = {
+               typeId: null,
+               properties: null,
+               typeTree: [],
+               doc: null
+       };
+
+       /**
+        * Prototypes a TS reference type object
+        *
+        * @param {String} typeId
+        */
+       TsRef.TsRefType = function(typeId) {
+               this.typeId = typeId;
+               this.properties = [];
+       };
+
+       /**
+        * Prototypes a TS reference property object
+        *
+        * @param {String} parentType
+        * @param {String} name
+        * @param {String} value
+        * @constructor
+        */
+       TsRef.TsRefProperty = function(parentType, name, value) {
+               this.parentType = parentType;
+               this.name = name;
+               this.value = value;
+       };
+
+       /**
+        * Load available TypoScript reference
+        */
+       TsRef.loadTsrefAsync = function() {
+               $.ajax({
+                       url: TYPO3.settings.ajaxUrls['t3editor_tsref'],
+                       success: function(response) {
+                               TsRef.doc = response;
+                               TsRef.buildTree();
+                       }
+               });
+       };
+
+       /**
+        * Build the TypoScript reference tree
+        */
+       TsRef.buildTree = function() {
+               for (var typeId in TsRef.doc) {
+                       var arr = TsRef.doc[typeId];
+                       TsRef.typeTree[typeId] = new TsRef.TsRefType(typeId);
+
+                       if (typeof arr['extends'] !== 'undefined') {
+                               TsRef.typeTree[typeId]['extends'] = arr['extends'];
+                       }
+                       for (var propName in arr.properties) {
+                               var propType = arr.properties[propName].type;
+                               TsRef.typeTree[typeId].properties[propName] = new TsRef.TsRefProperty(typeId, propName, propType);
+                       }
+               }
+               for (var typeId in TsRef.typeTree) {
+                       if (typeof TsRef.typeTree[typeId]['extends'] !== 'undefined') {
+                               TsRef.addPropertiesToType(TsRef.typeTree[typeId], TsRef.typeTree[typeId]['extends'], 100);
+                       }
+               }
+       };
+
+       /**
+        * Adds properties to TypoScript types
+        *
+        * @param {String} addToType
+        * @param {String} addFromTypeNames
+        * @param {Number} maxRecDepth
+        */
+       TsRef.addPropertiesToType = function(addToType, addFromTypeNames, maxRecDepth) {
+               if (maxRecDepth < 0) {
+                       throw "Maximum recursion depth exceeded while trying to resolve the extends in the TSREF!";
+                       return;
+               }
+               var exts = addFromTypeNames.split(','),
+                       i;
+               for (i = 0; i < exts.length; i++) {
+                       // "Type 'array' which is used to extend 'undefined', was not found in the TSREF!"
+                       if (typeof TsRef.typeTree[exts[i]] !== 'undefined') {
+                               if (typeof TsRef.typeTree[exts[i]]['extends'] !== 'undefined') {
+                                       TsRef.addPropertiesToType(TsRef.typeTree[exts[i]], TsRef.typeTree[exts[i]]['extends'], maxRecDepth-1);
+                               }
+                               var properties = TsRef.typeTree[exts[i]].properties;
+                               for (var propName in properties) {
+                                       // only add this property if it was not already added by a supertype (subtypes override supertypes)
+                                       if (typeof addToType.properties[propName] === 'undefined') {
+                                               addToType.properties[propName] = properties[propName];
+                                       }
+                               }
+                       }
+               }
+       };
+
+       /**
+        * Get properties from given TypoScript type id
+        *
+        * @param {String} tId
+        * @return {Array}
+        */
+       TsRef.getPropertiesFromTypeId = function(tId) {
+               if (typeof TsRef.typeTree[tId] !== 'undefined') {
+                       // clone is needed to assure that nothing of the tsref is overwritten by user setup
+                       TsRef.typeTree[tId].properties.clone = function() {
+                               var result = [];
+                               for (key in this) {
+                                       result[key] = new TsRef.TsRefProperty(this[key].parentType, this[key].name, this[key].value);
+                               }
+                               return result;
+                       }
+                       return TsRef.typeTree[tId].properties;
+               }
+               return [];
+       };
+
+       /**
+        * Check if a property of a type exists
+        *
+        * @param {String} typeId
+        * @param {String} propertyName
+        * @return {Boolean}
+        */
+       TsRef.typeHasProperty = function(typeId, propertyName) {
+               return typeof TsRef.typeTree[typeId] !== 'undefined'
+                       && typeof TsRef.typeTree[typeId].properties[propertyName] !== 'undefined';
+       };
+
+       /**
+        * Get the type
+        *
+        * @param {String} typeId
+        * @return {Object}
+        */
+       TsRef.getType = function(typeId) {
+               return TsRef.typeTree[typeId];
+       };
+
+       /**
+        * Check if type exists in the type tree
+        *
+        * @param {String} typeId
+        * @return {Boolean}
+        */
+       TsRef.isType = function(typeId) {
+               return typeof TsRef.typeTree[typeId] !== 'undefined';
+       };
+
+       return TsRef;
+});
\ No newline at end of file
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/TypoScriptHint.js b/typo3/sysext/t3editor/Resources/Public/JavaScript/Addon/Hint/TypoScriptHint.js
new file mode 100644 (file)
index 0000000..29019c4
--- /dev/null
@@ -0,0 +1,105 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function (mod) {
+       if (typeof exports === 'object' && typeof module === 'object') // CommonJS
+               mod(require('cm/lib/codemirror', 'TYPO3/CMS/T3editor/Addon/Hint/TsCodeCompletion'));
+       else if (typeof define === 'function' && define.amd) // AMD
+               define(['cm/lib/codemirror', 'TYPO3/CMS/T3editor/Addon/Hint/TsCodeCompletion'], mod);
+       else // Plain browser env
+               mod(CodeMirror);
+})(function (CodeMirror, TsCodeCompletion) {
+       var Pos = CodeMirror.Pos;
+
+       CodeMirror.registerHelper('hint', 'typoscript', function (editor, options) {
+               return typoScriptHint(editor, function (e, cur) {
+                       return e.getTokenAt(cur);
+               }, options);
+       });
+
+       function arrayContains(arr, item) {
+               if (!Array.prototype.indexOf) {
+                       var i = arr.length;
+                       while (i--) {
+                               if (arr[i] === item) {
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
+               return arr.indexOf(item) !== -1;
+       }
+
+       function typoScriptHint(editor, getToken) {
+               var keywords = TsCodeCompletion.refreshCodeCompletion(editor);
+
+               // Find the token at the cursor
+               var cur = editor.getCursor(),
+                       token = getToken(editor, cur);
+
+               if (/\b(?:string|comment)\b/.test(token.type) && tokenIsSubStringOfKeywords(token, keywords)) {
+                       return;
+               }
+               token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;
+
+               // If it's not a 'word-style' token, ignore the token.
+               if (!/^[\w$_]*$/.test(token.string)) {
+                       token = {
+                               start: cur.ch, end: cur.ch, string: '', state: token.state,
+                               type: token.string === '.' ? 'property' : null
+                       };
+               } else if (token.end > cur.ch) {
+                       token.end = cur.ch;
+                       token.string = token.string.slice(0, cur.ch - token.start);
+               }
+
+               var completions = {
+                       list: getCompletions(token, keywords),
+                       from: Pos(cur.line, token.start),
+                       to: Pos(cur.line, token.end)
+               };
+
+               CodeMirror.on(completions, 'pick', function() {
+                       TsCodeCompletion.resetCompList();
+               });
+
+               return completions;
+       }
+
+       function tokenIsSubStringOfKeywords(token, keywords) {
+               var tokenLength = token.string.length;
+               for (var i = 0; i < keywords.length; ++i) {
+                       if (token.string === keywords[i].substr(tokenLength)) {
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+
+       function getCompletions(token, keywords) {
+               var found = [],
+                       start = token.string;
+
+               function maybeAdd(str) {
+                       if (str.lastIndexOf(start, 0) === 0 && !arrayContains(found, str)) {
+                               found.push(str);
+                       }
+               }
+
+               // If not, just look in the global object and any local scope
+               // (reading into JS mode internals to get at the local and global variables)
+               for (var v = token.state.localVars; v; v = v.next) {
+                       maybeAdd(v.name);
+               }
+               for (var v = token.state.globalVars; v; v = v.next) {
+                       maybeAdd(v.name);
+               }
+               for (var i = 0, e = keywords.length; i < e; ++i) {
+                       maybeAdd(keywords[i]);
+               }
+               found.sort();
+
+               return found;
+       }
+});
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/AUTHORS b/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/AUTHORS
new file mode 100644 (file)
index 0000000..07b8fbd
--- /dev/null
@@ -0,0 +1,671 @@
+List of CodeMirror contributors. Updated before every release.
+
+4r2r
+Aaron Brooks
+Abdelouahab
+Abe Fettig
+Adam Ahmed
+Adam King
+Adam Particka
+adanlobato
+Adán Lobato
+Adrian Aichner
+Adrian Heine
+Adrien Bertrand
+aeroson
+Ahmad Amireh
+Ahmad M. Zawawi
+ahoward
+Akeksandr Motsjonov
+Alasdair Smith
+Alberto González Palomo
+Alberto Pose
+Albert Xing
+Alexander Pavlov
+Alexander Schepanovski
+Alexander Shvets
+Alexander Solovyov
+Alexandre Bique
+alexey-k
+Alex Piggott
+Aliaksei Chapyzhenka
+Allen Sarkisyan
+Ami Fischman
+Amin Shali
+Amin Ullah Khan
+amshali@google.com
+Amsul
+amuntean
+Amy
+Ananya Sen
+anaran
+AndersMad
+Anders Nawroth
+Anderson Mesquita
+Anders Wåglund
+Andrea G
+Andreas Reischuck
+Andres Taylor
+Andre von Houck
+Andrew Cheng
+Andrey Fedorov
+Andrey Klyuchnikov
+Andrey Lushnikov
+Andrey Shchekin
+Andy Joslin
+Andy Kimball
+Andy Li
+Angelo
+angelozerr
+angelo.zerr@gmail.com
+Ankit
+Ankit Ahuja
+Ansel Santosa
+Anthony Dugois
+anthonygego
+Anthony Gégo
+Anthony Grimes
+Anton Kovalyov
+Apollo Zhu
+AQNOUCH Mohammed
+areos
+Arnab Bose
+Arsène von Wyss
+Arthur Müller
+Arun Narasani
+as3boyan
+asolove
+atelierbram
+AtomicPages LLC
+Atul Bhouraskar
+Aurelian Oancea
+Axel Lewenhaupt
+Barret Rennie
+Basarat Ali Syed
+Bastian Müller
+belhaj
+Bem Jones-Bey
+benbro
+Beni Cherniavsky-Paskin
+Benjamin DeCoste
+Benjamin Young
+Ben Keen
+Ben Miller
+Ben Mosher
+Bernhard Sirlinger
+Bert Chang
+Bharad
+BigBlueHat
+Billy Moon
+binny
+B Krishna Chaitanya
+Blaine G
+blukat29
+boomyjee
+borawjm
+Brad Metcalf
+Brandon Frohs
+Brandon Wamboldt
+Brett Zamir
+Brian Grinstead
+Brian Sletten
+brrd
+Bruce Mitchener
+Bryan Massoth
+Caitlin Potter
+Calin Barbat
+callodacity
+Camilo Roca
+Chad Jolly
+Chandra Sekhar Pydi
+Charles Skelton
+Cheah Chu Yeow
+Chris Coyier
+Chris Ford
+Chris Granger
+Chris Houseknecht
+Chris Lohfink
+Chris Morgan
+Chris Smith
+Christian Oyarzun
+Christian Petrov
+Christopher Brown
+Christopher Kramer
+Christopher Mitchell
+Christopher Pfohl
+Chunliang Lyu
+ciaranj
+CodeAnimal
+coderaiser
+Cole R Lawrence
+ComFreek
+Curtis Gagliardi
+dagsta
+daines
+Dale Jung
+Dan Bentley
+Dan Heberden
+Daniel, Dao Quang Minh
+Daniele Di Sarli
+Daniel Faust
+Daniel Huigens
+Daniel Kesler
+Daniel KJ
+Daniel Neel
+Daniel Parnell
+Danila Malyutin
+Danny Yoo
+darealshinji
+Darius Roberts
+Dave Brondsema
+Dave Myers
+David Barnett
+David H. Bronke
+David Mignot
+David Pathakjee
+David Vázquez
+David Whittington
+deebugger
+Deep Thought
+Devin Abbott
+Devon Carew
+Dick Choi
+dignifiedquire
+Dimage Sapelkin
+Dmitry Kiselyov
+domagoj412
+Dominator008
+Domizio Demichelis
+Doug Wikle
+Drew Bratcher
+Drew Hintz
+Drew Khoury
+Drini Cami
+Dror BG
+duralog
+dwelle
+eborden
+edsharp
+ekhaled
+Elisée
+Emmanuel Schanzer
+Enam Mijbah Noor
+Eric Allam
+Erik Welander
+eustas
+Fabien Dubosson
+Fabien O'Carroll
+Fabio Zendhi Nagao
+Faiza Alsaied
+Fauntleroy
+fbuchinger
+feizhang365
+Felipe Lalanne
+Felix Raab
+ficristo
+Filip Noetzel
+Filip Stollár
+flack
+Florian Felten
+ForbesLindesay
+Forbes Lindesay
+Ford_Lawnmower
+Forrest Oliphant
+Frank Wiegand
+Gabriel Gheorghian
+Gabriel Horner
+Gabriel Nahmias
+galambalazs
+Gary Sheng
+Gautam Mehta
+Gavin Douglas
+gekkoe
+Geordie Hall
+George Stephanis
+geowarin
+Gerard Braad
+Gergely Hegykozi
+Giovanni Calò
+Glebov Boris
+Glenn Jorde
+Glenn Ruehle
+Golevka
+Google Inc.
+Gordon Smith
+Grant Skinner
+greengiant
+Gregory Koberger
+Grzegorz Mazur
+Guillaume Massé
+Guillaume Massé
+guraga
+Gustavo Rodrigues
+Hakan Tunc
+Hans Engel
+Hardest
+Harshvardhan Gupta
+Hasan Karahan
+Hector Oswaldo Caballero
+Hendrik Wallbaum
+Herculano Campos
+Hiroyuki Makino
+hitsthings
+Hocdoc
+Hugues Malphettes
+Ian Beck
+Ian Dickinson
+Ian Wehrman
+Ian Wetherbee
+Ice White
+ICHIKAWA, Yuji
+idleberg
+ilvalle
+Ingo Richter
+Irakli Gozalishvili
+Ivan Kurnosov
+Ivoah
+Jacob Lee
+Jaimin
+Jake Peyser
+Jakob Miland
+Jakub Vrana
+Jakub Vrána
+James Campos
+James Howard
+James Thorne
+Jamie Hill
+Jamie Morris
+Jan Jongboom
+jankeromnes
+Jan Keromnes
+Jan Odvarko
+Jan Schär
+Jan T. Sott
+Jared Dean
+Jared Forsyth
+Jared Jacobs
+Jason
+Jason Barnabe
+Jason Grout
+Jason Johnston
+Jason San Jose
+Jason Siefken
+Jaydeep Solanki
+Jean Boussier
+Jeff Blaisdell
+Jeff Jenkins
+jeffkenton
+Jeff Pickhardt
+jem (graphite)
+Jeremy Parmenter
+Jim
+Jim Avery
+JobJob
+jochenberger
+Jochen Berger
+Joel Einbinder
+joelpinheiro
+Johan Ask
+John Connor
+John-David Dalton
+John Engler
+John Lees-Miller
+John Snelson
+John Van Der Loo
+Jon Ander Peñalba
+Jonas Döbertin
+Jonathan Malmaud
+Jon Gacnik
+jongalloway
+Jon Malmaud
+Jon Sangster
+Joost-Wim Boekesteijn
+Joseph Pecoraro
+Josh Barnes
+Josh Cohen
+Josh Soref
+Joshua Newman
+Josh Watzman
+jots
+jsoojeon
+ju1ius
+Juan Benavides Romero
+Jucovschi Constantin
+Juho Vuori
+Julien Rebetez
+Justin Andresen
+Justin Hileman
+jwallers@gmail.com
+kaniga
+karevn
+Kayur Patel
+Kazuhito Hokamura
+Ken Newman
+ken restivo
+Ken Rockot
+Kevin Earls
+Kevin Kwok
+Kevin Muret
+Kevin Sawicki
+Kevin Ushey
+Klaus Silveira
+Koh Zi Han, Cliff
+komakino
+Konstantin Lopuhin
+koops
+Kris Ciccarello
+ks-ifware
+kubelsmieci
+KwanEsq
+Kyle Kelley
+KyleMcNutt
+Lanfei
+Lanny
+Laszlo Vidacs
+leaf corcoran
+Leonid Khachaturov
+Leon Sorokin
+Leonya Khachaturov
+Liam Newman
+Libo Cannici
+LloydMilligan
+LM
+lochel
+Lorenzo Stoakes
+Luca Fabbri
+Luciano Longo
+Lu Fangjian
+Luke Browning
+Luke Granger-Brown
+Luke Stagner
+lynschinzer
+M1cha
+Madhura Jayaratne
+Maksim Lin
+Maksym Taran
+Malay Majithia
+Manideep
+Manuel Rego Casasnovas
+Marat Dreizin
+Marcel Gerber
+Marcelo Camargo
+Marco Aurélio
+Marco Munizaga
+Marcus Bointon
+Marek Rudnicki
+Marijn Haverbeke
+Mário Gonçalves
+Mario Pietsch
+Mark Anderson
+Mark Lentczner
+Marko Bonaci
+Mark Peace
+Markus Bordihn
+Martin Balek
+Martín Gaitán
+Martin Hasoň
+Martin Hunt
+Martin Laine
+Martin Zagora
+Mason Malone
+Mateusz Paprocki
+Mathias Bynens
+mats cronqvist
+Matt Gaide
+Matthew Bauer
+Matthew Beale
+matthewhayes
+Matthew Rathbone
+Matthias Bussonnier
+Matthias BUSSONNIER
+Matt McDonald
+Matt Pass
+Matt Sacks
+mauricio
+Maximilian Hils
+Maxim Kraev
+Max Kirsch
+Max Schaefer
+Max Xiantu
+mbarkhau
+McBrainy
+mce2
+melpon
+Metatheos
+Micah Dubinko
+Michael
+Michael Goderbauer
+Michael Grey
+Michael Kaminsky
+Michael Lehenbauer
+Michael Zhou
+Michal Čihař
+Michal Dorner
+Mighty Guava
+Miguel Castillo
+mihailik
+Mike
+Mike Brevoort
+Mike Diaz
+Mike Ivanov
+Mike Kadin
+Mike Kobit
+MinRK
+Miraculix87
+misfo
+mkaminsky11
+mloginov
+Moritz Schwörer
+mps
+ms
+mtaran-google
+Mu-An Chiou
+mzabuawala
+Narciso Jaramillo
+Nathan Williams
+ndr
+nerbert
+NetworkNode
+nextrevision
+ngn
+nguillaumin
+Ng Zhi An
+Nicholas Bollweg
+Nicholas Bollweg (Nick)
+Nick Kreeger
+Nick Small
+Nicolas Kick
+Nicolò Ribaudo
+Niels van Groningen
+nightwing
+Nikita Beloglazov
+Nikita Vasilyev
+Nikolay Kostov
+nilp0inter
+Nisarg Jhaveri
+nlwillia
+noragrossman
+Norman Rzepka
+opl-
+Oreoluwa Onatemowo
+Oskar Segersvärd
+pablo
+pabloferz
+Pablo Zubieta
+Page
+paladox
+Panupong Pasupat
+paris
+Paris
+Paris Kasidiaris
+Patil Arpith
+Patrick Stoica
+Patrick Strawderman
+Paul Garvin
+Paul Ivanov
+Paul Masson
+Pavel
+Pavel Feldman
+Pavel Petržela
+Pavel Strashkin
+Paweł Bartkiewicz
+peteguhl
+peter
+Peter Flynn
+peterkroon
+Peter Kroon
+Philipp A
+Philip Stadermann
+Pierre Gerold
+Piët Delport
+Pontus Melke
+prasanthj
+Prasanth J
+Prayag Verma
+Radek Piórkowski
+Rahul
+Rahul Anand
+ramwin1
+Randall Mason
+Randy Burden
+Randy Edmunds
+Rasmus Erik Voel Jensen
+Rasmus Schultz
+ray ratchup
+Ray Ratchup
+Remi Nyborg
+Renaud Durlin
+Richard Denton
+Richard van der Meer
+Richard Z.H. Wang
+Rishi Goomar
+Robert Brignull
+Robert Crossfield
+Roberto Abdelkader Martínez Pérez
+robertop23
+Robert Plummer
+Rrandom
+Rrrandom
+Ruslan Osmanov
+Ryan Petrello
+Ryan Prior
+sabaca
+Sam Lee
+Sam Rawlins
+Samuel Ainsworth
+Sam Wilson
+sandeepshetty
+Sander AKA Redsandro
+Sander Verweij
+santec
+Sascha Peilicke
+satamas
+satchmorun
+sathyamoorthi
+Saul Costa
+S. Chris Colbert
+SCLINIC\jdecker
+Scott Aikin
+Scott Goodhew
+Sebastian Zaha
+Sergey Goder
+Sergey Tselovalnikov
+Se-Won Kim
+shaund
+shaun gilchrist
+Shawn A
+Shea Bunge
+sheopory
+Shil S
+Shiv Deepak
+Shmuel Englard
+Shubham Jain
+Siamak Mokhtari
+silverwind
+Simon Edwards
+sinkuu
+snasa
+soliton4
+sonson
+spastorelli
+srajanpaliwal
+Stanislav Oaserele
+Stas Kobzar
+Stefan Borsje
+Steffen Beyer
+Steffen Bruchmann
+Stephen Lavelle
+Steve Champagne
+Steve Hoover
+Steve O'Hara
+stoskov
+Stu Kennedy
+Sungho Kim
+sverweij
+Taha Jahangir
+takamori
+Tako Schotanus
+Takuji Shimokawa
+Takuya Matsuyama
+Tarmil
+TDaglis
+tel
+Tentone
+tfjgeorge
+Thaddee Tyl
+thanasis
+TheHowl
+themrmax
+think
+Thomas Dvornik
+Thomas Kluyver
+Thomas Schmid
+Tim Alby
+Tim Baumann
+Timothy Farrell
+Timothy Gu
+Timothy Hatcher
+TobiasBg
+Todd Berman
+Todd Kennedy
+Tomas-A
+Tomas Varaneckas
+Tom Erik Støwer
+Tom Klancer
+Tom MacWright
+Tony Jian
+Travis Heppe
+Triangle717
+Tristan Tarrant
+TSUYUSATO Kitsune
+twifkak
+Tyler Long
+VapidWorx
+Vestimir Markov
+vf
+Victor Bocharsky
+Vincent Woo
+Volker Mische
+Weiyan Shao
+wenli
+Wes Cossick
+Wesley Wiser
+Will Binns-Smith
+Will Dean
+William Jamieson
+William Stein
+Willy
+Wojtek Ptak
+Wu Cheng-Han
+Xavier Mendez
+Yassin N. Hassan
+YNH Webdev
+Yunchi Luo
+Yuvi Panda
+Zac Anger
+Zachary Dremann
+Zeno Rocha
+Zhang Hao
+Ziv
+zziuni
+魏鹏刚
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/CHANGELOG.md b/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/CHANGELOG.md
new file mode 100644 (file)
index 0000000..2c0887e
--- /dev/null
@@ -0,0 +1,1188 @@
+## 5.28.0 (2017-07-21)
+
+### Bug fixes
+
+Fix copying of, or replacing editor content with, a single dash character when copying a big selection in some corner cases.
+
+Make [`"goLineLeft"`](http://codemirror.net/doc/manual.html#command_goLineLeft)/`"goLineRight"` behave better on wrapped lines.
+
+[sql mode](http://codemirror.net/mode/sql/): Fix tokenizing of multi-dot operator and allow digits in subfield names.
+
+[searchcursor addon](http://codemirror.net/doc/manual.html#addon_searchcursor): Fix infinite loop on some composed character inputs.
+
+[markdown mode](http://codemirror.net/mode/markdown/): Make list parsing more CommonMark-compliant.
+
+[gfm mode](http://codemirror.net/mode/gfm/): Highlight colon syntax for emoji.
+
+### New features
+
+Expose [`startOperation`](http://codemirror.net/doc/manual.html#startOperation) and `endOperation` for explicit operation management.
+
+[sublime bindings](http://codemirror.net/demo/sublime.html): Add extend-selection (Ctrl-Alt- or Cmd-Shift-Up/Down).
+
+## 5.27.4 (2017-06-29)
+
+### Bug fixes
+
+Fix crash when using mode lookahead.
+
+[markdown mode](http://codemirror.net/mode/markdown/): Don't block inner mode's indentation support.
+
+## 5.27.2 (2017-06-22)
+
+### Bug fixes
+
+Fix crash in the [simple mode](http://codemirror.net/demo/simplemode.html) addon.
+
+## 5.27.0 (2017-06-22)
+
+### Bug fixes
+
+Fix infinite loop in forced display update.
+
+Properly disable the hidden textarea when `readOnly` is `"nocursor"`.
+
+Calling the `Doc` constructor without `new` works again.
+
+[sql mode](http://codemirror.net/mode/sql/): Handle nested comments.
+
+[javascript mode](http://codemirror.net/mode/javascript/): Improve support for TypeScript syntax.
+
+[markdown mode](http://codemirror.net/mode/markdown/): Fix bug where markup was ignored on indented paragraph lines.
+
+[vim bindings](http://codemirror.net/mode/demo/vim.html): Referencing invalid registers no longer causes an uncaught exception.
+
+[rust mode](http://codemirror.net/mode/rust/): Add the correct MIME type.
+
+[matchbrackets addon](http://codemirror.net/doc/manual.html#addon_matchbrackets): Document options.
+
+### New features
+
+Mouse button clicks can now be bound in keymaps by using names like `"LeftClick"` or `"Ctrl-Alt-MiddleTripleClick"`. When bound to a function, that function will be passed the position of the click as second argument.
+
+The behavior of mouse selection and dragging can now be customized with the [`configureMouse`](http://codemirror.net/doc/manual.html#option_configureMouse) option.
+
+Modes can now look ahead across line boundaries with the [`StringStream`](http://codemirror.net/doc/manual.html#StringStream)`.lookahead` method.
+
+Introduces a `"type"` token type, makes modes that recognize types output it, and add styling for it to the themes.
+
+New [`pasteLinesPerSelection`](http://codemirror.net/doc/manual.html#option_pasteLinesPerSelection) option to control the behavior of pasting multiple lines into multiple selections.
+
+[searchcursor addon](http://codemirror.net/doc/manual.html#addon_searchcursor): Support multi-line regular expression matches, and normalize strings when matching.
+
+## 5.26.0 (2017-05-22)
+
+### Bug fixes
+
+In textarea-mode, don't reset the input field during composition.
+
+More careful restoration of selections in widgets, during editor redraw.
+
+[javascript mode](http://codemirror.net/mode/javascript/): More TypeScript parsing fixes.
+
+[julia mode](http://codemirror.net/mode/julia/): Fix issue where the mode gets stuck.
+
+[markdown mode](http://codemirror.net/mode/markdown/): Understand cross-line links, parse all bracketed things as links.
+
+[soy mode](http://codemirror.net/mode/soy/): Support single-quoted strings.
+
+[go mode](http://codemirror.net/mode/go/): Don't try to indent inside strings or comments.
+
+### New features
+
+[vim bindings](http://codemirror.net/mode/demo/vim.html): Parse line offsets in line or range specs.
+
+## 5.25.2 (2017-04-20)
+
+### Bug fixes
+
+Better handling of selections that cover the whole viewport in contentEditable-mode.
+
+No longer accidentally scroll the editor into view when calling `setValue`.
+
+Work around Chrome Android bug when converting screen coordinates to editor positions.
+
+Make sure long-clicking a selection sets a cursor and doesn't show the editor losing focus.
+
+Fix issue where pointer events were incorrectly disabled on Chrome's overlay scrollbars.
+
+[javascript mode](http://codemirror.net/mode/javascript/): Recognize annotations and TypeScript-style type parameters.
+
+[shell mode](http://codemirror.net/mode/shell/): Handle nested braces.
+
+[markdown mode](http://codemirror.net/mode/markdown/): Make parsing of strong/em delimiters CommonMark-compliant.
+
+## 5.25.0 (2017-03-20)
+
+### Bug fixes
+
+In contentEditable-mode, properly locate changes that repeat a character when inserted with IME.
+
+Fix handling of selections bigger than the viewport in contentEditable mode.
+
+Improve handling of changes that insert or delete lines in contentEditable mode.
+
+Count Unicode control characters 0x80 to 0x9F as special (non-printing) chars.
+
+Fix handling of shadow DOM roots when finding the active element.
+
+Add `role=presentation` to more DOM elements to improve screen reader support.
+
+[merge addon](http://codemirror.net/doc/manual.html#addon_merge): Make aligning of unchanged chunks more robust.
+
+[comment addon](http://codemirror.net/doc/manual.html#addon_comment): Fix comment-toggling on a block of text that starts and ends in a (differnet) block comment.
+
+[javascript mode](http://codemirror.net/mode/javascript/): Improve support for TypeScript syntax.
+
+[r mode](http://codemirror.net/mode/r/): Fix indentation after semicolon-less statements.
+
+[shell mode](http://codemirror.net/mode/shell/): Properly handle escaped parentheses in parenthesized expressions.
+
+[markdown mode](http://codemirror.net/mode/markdown/): Fix a few bugs around leaving fenced code blocks.
+
+[soy mode](http://codemirror.net/mode/soy/): Improve indentation.
+
+### New features
+
+[lint addon](http://codemirror.net/doc/manual.html#addon_lint): Support asynchronous linters that return promises.
+
+[continuelist addon](http://codemirror.net/doc/manual.html#addon_continuelist): Support continuing task lists.
+
+[vim bindings](http://codemirror.net/mode/demo/vim.html): Make Y behave like yy.
+
+[sql mode](http://codemirror.net/mode/sql/): Support sqlite dialect.
+
+## 5.24.2 (2017-02-22)
+
+### Bug fixes
+
+[javascript mode](http://codemirror.net/mode/javascript/): Support computed class method names.
+
+[merge addon](http://codemirror.net/doc/manual.html#addon_merge): Improve aligning of unchanged code in the presence of marks and line widgets.
+
+## 5.24.0 (2017-02-20)
+
+### Bug fixes
+
+A cursor directly before a line-wrapping break is now drawn before or after the line break depending on which direction you arrived from.
+
+Visual cursor motion in line-wrapped right-to-left text should be much more correct.
+
+Fix bug in handling of read-only marked text.
+
+[shell mode](http://codemirror.net/mode/shell/): Properly tokenize nested parentheses.
+
+[python mode](http://codemirror.net/mode/python/): Support underscores in number literals.
+
+[sass mode](http://codemirror.net/mode/sass/): Uses the full list of CSS properties and keywords from the CSS mode, rather than defining its own incomplete subset.
+
+[css mode](http://codemirror.net/mode/css/): Expose `lineComment` property for LESS and SCSS dialects. Recognize vendor prefixes on pseudo-elements.
+
+[julia mode](http://codemirror.net/mode/julia/): Properly indent `elseif` lines.
+
+[markdown mode](http://codemirror.net/mode/markdown/): Properly recognize the end of fenced code blocks when inside other markup.
+
+[scala mode](http://codemirror.net/mode/clike/): Improve handling of operators containing <code>#</code>, <code>@</code>, and <code>:</code> chars.
+
+[xml mode](http://codemirror.net/mode/xml/): Allow dashes in HTML tag names.
+
+[javascript mode](http://codemirror.net/mode/javascript/): Improve parsing of async methods, TypeScript-style comma-separated superclass lists.
+
+[indent-fold addon](http://codemirror.net/demo/folding.html): Ignore comment lines.
+
+### New features
+
+Positions now support a `sticky` property which determines whether they should be associated with the character before (value `"before"`) or after (value `"after"`) them.
+
+[vim bindings](http://codemirror.net/mode/demo/vim.html): Make it possible to remove built-in bindings through the API.
+
+[comment addon](http://codemirror.net/doc/manual.html#addon_comment): Support a per-mode <code>useInnerComments</code> option to optionally suppress descending to the inner modes to get comment strings.
+
+### Breaking changes
+
+The [sass mode](http://codemirror.net/mode/sass/) now depends on the [css mode](http://codemirror.net/mode/css/).
+
+## 5.23.0 (2017-01-19)
+
+### Bug fixes
+
+Presentation-related elements DOM elements are now marked as such to help screen readers.
+
+[markdown mode](http://codemirror.net/mode/markdown/): Be more picky about what HTML tags look like to avoid false positives.
+
+### New features
+
+`findModeByMIME` now understands `+json` and `+xml` MIME suffixes.
+
+[closebrackets addon](http://codemirror.net/doc/manual.html#addon_closebrackets): Add support for an `override` option to ignore language-specific defaults.
+
+[panel addon](http://codemirror.net/doc/manual.html#addon_panel): Add a `stable` option that auto-scrolls the content to keep it in the same place when inserting/removing a panel.
+
+## 5.22.2 (2017-01-12)
+
+### Bug fixes
+
+Include rollup.config.js in NPM package, so that it can be used to build from source.
+
+## 5.22.0 (2016-12-20)
+
+### Bug fixes
+
+[sublime bindings](http://codemirror.net/demo/sublime.html): Make `selectBetweenBrackets` work with multiple cursors.
+
+[javascript mode](http://codemirror.net/mode/javascript/): Fix issues with parsing complex TypeScript types, imports, and exports.
+
+A contentEditable editor instance with autofocus enabled no longer crashes during initializing.
+
+### New features
+
+[emacs bindings](http://codemirror.net/demo/emacs.html): Export `CodeMirror.emacs` to allow other addons to hook into Emacs-style functionality.
+
+[active-line addon](http://codemirror.net/doc/manual.html#addon_active-line): Add `nonEmpty` option.
+
+New event: [`optionChange`](http://codemirror.net/doc/manual.html#event_optionChange).
+
+## 5.21.0 (2016-11-21)
+
+### Bug fixes
+
+Tapping/clicking the editor in [contentEditable mode](http://codemirror.net/doc/manual.html#option_inputStyle) on Chrome now puts the cursor at the tapped position.
+
+Fix various crashes and misbehaviors when reading composition events in [contentEditable mode](http://codemirror.net/doc/manual.html#option_inputStyle).
+
+Catches and ignores an IE 'Unspecified Error' when creating an editor in an iframe before there is a `<body>`.
+
+[merge addon](http://codemirror.net/doc/manual.html#addon_merge): Fix several issues in the chunk-aligning feature.
+
+[verilog mode](http://codemirror.net/mode/verilog): Rewritten to address various issues.
+
+[julia mode](http://codemirror.net/mode/julia): Recognize Julia 0.5 syntax.
+
+[swift mode](http://codemirror.net/mode/swift): Various fixes and adjustments to current syntax.
+
+[markdown mode](http://codemirror.net/mode/markdown): Allow lists without a blank line above them.
+
+### New features
+
+The [`setGutterMarker`](http://codemirror.net/doc/manual.html#setGutterMarker), [`clearGutter`](http://codemirror.net/doc/manual.html#clearGutter), and [`lineInfo`](http://codemirror.net/doc/manual.html#lineInfo) methods are now available on `Doc` objects.
+
+The [`heightAtLine`](http://codemirror.net/doc/manual.html#heightAtLine) method now takes an extra argument to allow finding the height at the top of the line's line widgets.
+
+[ruby mode](http://codemirror.net/mode/ruby): `else` and `elsif` are now immediately indented.
+
+[vim bindings](http://codemirror.net/demo/vim.html): Bind Ctrl-T and Ctrl-D to in- and dedent in insert mode.
+
+## 5.20.2 (2016-10-21)
+
+### Bug fixes
+
+Fix `CodeMirror.version` returning the wrong version number.
+
+## 5.20.0 (2016-10-20)
+
+### Bug fixes
+
+Make `newlineAndIndent` command work with multiple cursors on the same line.
+
+Make sure keypress events for backspace are ignored.
+
+Tokens styled with overlays no longer get a nonsense `cm-cm-overlay` class.
+
+Line endings for pasted content are now normalized to the editor's [preferred ending](http://codemirror.net/doc/manual.html#option_lineSeparator).
+
+[javascript mode](http://codemirror.net/mode/javascript): Improve support for class expressions. Support TypeScript optional class properties, the `abstract` keyword, and return type declarations for arrow functions.
+
+[css mode](http://codemirror.net/mode/css): Fix highlighting of mixed-case keywords.
+
+[closebrackets addon](http://codemirror.net/doc/manual.html#addon_closebrackets): Improve behavior when typing a quote before a string.
+
+### New features
+
+The core is now maintained as a number of small files, using ES6 syntax and modules, under the `src/` directory. A git checkout no longer contains a working `codemirror.js` until you `npm build` (but when installing from NPM, it is included).
+
+The [`refresh`](http://codemirror.net/doc/manual.html#event_refresh) event is now documented and stable.
+
+## 5.19.0 (2016-09-20)
+
+### Bugfixes
+
+[erlang mode](http://codemirror.net/mode/erlang): Fix mode crash when trying to read an empty context.
+
+[comment addon](http://codemirror.net/doc/manual.html#addon_comment): Fix broken behavior when toggling comments inside a comment.
+
+xml-fold addon: Fix a null-dereference bug.
+
+Page up and page down now do something even in single-line documents.
+
+Fix an issue where the cursor position could be off in really long (~8000 character) tokens.
+
+### New features
+
+[javascript mode](http://codemirror.net/mode/javascript): Better indentation when semicolons are missing. Better support for TypeScript classes, optional parameters, and the `type` keyword.
+
+The [`blur`](http://codemirror.net/doc/manual.html#event_blur) and [`focus`](http://codemirror.net/doc/manual.html#event_focus) events now pass the DOM event to their handlers.
+
+## 5.18.2 (2016-08-23)
+
+### Bugfixes
+
+[vue mode](http://codemirror.net/mode/vue): Fix outdated references to renamed Pug mode dependency.
+
+## 5.18.0 (2016-08-22)
+
+### Bugfixes
+
+Make sure [gutter backgrounds](http://codemirror.net/doc/manual.html#addLineClass) stick to the rest of the gutter during horizontal scrolling.
+
+The contenteditable [`inputStyle`](http://codemirror.net/doc/manual.html#option_inputStyle) now properly supports pasting on pre-Edge IE versions.
+
+[javascript mode](http://codemirror.net/mode/javascript): Fix some small parsing bugs and improve TypeScript support.
+
+[matchbrackets addon](http://codemirror.net/doc/manual.html#addon_matchbrackets): Fix bug where active highlighting was left in editor when the addon was disabled.
+
+[match-highlighter addon](http://codemirror.net/doc/manual.html#addon_match-highlighter): Only start highlighting things when the editor gains focus.
+
+[javascript-hint addon](http://codemirror.net/doc/manual.html#addon_javascript-hint): Also complete non-enumerable properties.
+
+### New features
+
+The [`addOverlay`](http://codemirror.net/doc/manual.html#addOverlay) method now supports a `priority` option to control the order in which overlays are applied.
+
+MIME types that end in `+json` now default to the JSON mode when the MIME itself is not defined.
+
+### Breaking changes
+
+The mode formerly known as Jade was renamed to [Pug](http://codemirror.net/mode/pug).
+
+The [Python mode](http://codemirror.net/mode/python) now defaults to Python 3 (rather than 2) syntax.
+
+## 5.17.0 (2016-07-19)
+
+### Bugfixes
+
+Fix problem with wrapped trailing whitespace displaying incorrectly.
+
+Prevent IME dialog from overlapping typed content in Chrome.
+
+Improve measuring of characters near a line wrap.
+
+[javascript mode](http://codemirror.net/mode/javascript): Improve support for `async`, allow trailing commas in `import` lists.
+
+[vim bindings](http://codemirror.net/demo/vim.html): Fix backspace in replace mode.
+
+[sublime bindings](http://codemirror.net/demo/sublime.html): Fix some key bindings on OS X to match Sublime Text.
+
+### New features
+
+[markdown mode](http://codemirror.net/mode/markdown): Add more classes to image links in highlight-formatting mode.
+
+## 5.16.0 (2016-06-20)
+
+### Bugfixes
+
+Fix glitches when dragging content caused by the drop indicator receiving mouse events.
+
+Make Control-drag work on Firefox.
+
+Make clicking or selection-dragging at the end of a wrapped line select the right position.
+
+[show-hint addon](http://codemirror.net/doc/manual.html#addon_show-hint): Prevent widget scrollbar from hiding part of the hint text.
+
+[rulers addon](http://codemirror.net/doc/manual.html#addon_rulers): Prevent rulers from forcing a horizontal editor scrollbar.
+
+### New features
+
+[search addon](http://codemirror.net/doc/manual.html#addon_search): Automatically bind search-related keys in persistent dialog.
+
+[sublime keymap](http://codemirror.net/demo/sublime.html): Add a multi-cursor aware smart backspace binding.
+
+## 5.15.2 (2016-05-20)
+
+### Bugfixes
+
+Fix a critical document corruption bug that occurs when a document is gradually grown.
+
+## 5.15.0 (2016-05-20)
+
+### Bugfixes
+
+Fix bug that caused the selection to reset when focusing the editor in contentEditable input mode.
+
+Fix issue where not all ASCII control characters were being replaced by placeholders.
+
+Remove the assumption that all modes have a `startState` method from several wrapping modes.
+
+Fix issue where the editor would complain about overlapping collapsed ranges when there weren't any.
+
+Optimize document tree building when loading or pasting huge chunks of content.
+
+[markdown mode](http://codemirror.net/mode/markdown/): Fix several issues in matching link targets.
+
+[clike mode](http://codemirror.net/mode/clike/): Improve indentation of C++ template declarations.
+
+### New features
+
+Explicitly bind Ctrl-O on OS X to make that binding (“open line”) act as expected.
+
+Pasting [linewise-copied](http://codemirror.net/doc/manual.html#option_lineWiseCopyCut) content when there is no selection now inserts the lines above the current line.
+
+[javascript mode](http://codemirror.net/mode/javascript/): Support `async`/`await` and improve support for TypeScript type syntax.
+
+## 5.14.2 (2016-04-20)
+
+### Bugfixes
+
+Push a new package to NPM due to an [NPM bug](https://github.com/npm/npm/issues/5082) omitting the LICENSE file in 5.14.0.
+
+Set `dataTransfer.effectAllowed` in `dragstart` handler to help browsers use the right drag icon.
+
+Add the [mbox mode](http://codemirror.net/mode/mbox/index.html) to `mode/meta.js`.
+
+## 5.14.0 (2016-04-20)
+
+### Bugfixes
+
+[`posFromIndex`](http://codemirror.net/doc/manual.html#posFromIndex) and [`indexFromPos`](http://codemirror.net/doc/manual.html#indexFromPos) now take [`lineSeparator`](http://codemirror.net/doc/manual.html#option_lineSeparator) into account.
+
+[vim bindings](http://codemirror.net/demo/vim.html): Only call `.save()` when it is actually available.
+
+[comment addon](http://codemirror.net/doc/manual.html#addon_comment): Be careful not to mangle multi-line strings.
+
+[Python mode](http://codemirror.net/mode/python/index.html): Improve distinguishing of decorators from `@` operators.
+
+[`findMarks`](http://codemirror.net/doc/manual.html#findMarks): No longer return marks that touch but don't overlap given range.
+
+### New features
+
+[vim bindings](http://codemirror.net/demo/vim.html): Add yank command.
+
+[match-highlighter addon](http://codemirror.net/doc/manual.html#addon_match-highlighter): Add `trim` option to disable ignoring of whitespace.
+
+[PowerShell mode](http://codemirror.net/mode/powershell/index.html): Added.
+
+[Yacas mode](http://codemirror.net/mode/yacas/index.html): Added.
+
+[Web IDL mode](http://codemirror.net/mode/webidl/index.html): Added.
+
+[SAS mode](http://codemirror.net/mode/sas/index.html): Added.
+
+[mbox mode](http://codemirror.net/mode/mbox/index.html): Added.
+
+## 5.13.2 (2016-03-23)
+
+### Bugfixes
+
+Solves a problem where the gutter would sometimes not extend all the way to the end of the document.
+
+## 5.13.0 (2016-03-21)
+
+### New features
+
+New DOM event forwarded: [`"dragleave"`](http://codemirror.net/doc/manual.html#event_dom).
+
+[protobuf mode](http://codemirror.net/mode/protobuf/index.html): Newly added.
+
+### Bugfixes
+
+Fix problem where [`findMarks`](http://codemirror.net/doc/manual.html#findMarks) sometimes failed to find multi-line marks.
+
+Fix crash that showed up when atomic ranges and bidi text were combined.
+
+[show-hint addon](http://codemirror.net/demo/complete.html): Completion widgets no longer close when the line indented or dedented.
+
+[merge addon](http://codemirror.net/demo/merge.html): Fix bug when merging chunks at the end of the file.
+
+[placeholder addon](http://codemirror.net/doc/manual.html#addon_placeholder): No longer gets confused by [`swapDoc`](http://codemirror.net/doc/manual.html#swapDoc).
+
+[simplescrollbars addon](http://codemirror.net/doc/manual.html#addon_simplescrollbars): Fix invalid state when deleting at end of document.
+
+[clike mode](http://codemirror.net/mode/clike/index.html): No longer gets confused when a comment starts after an operator.
+
+[markdown mode](http://codemirror.net/mode/markdown/index.html): Now supports CommonMark-style flexible list indentation.
+
+[dylan mode](http://codemirror.net/mode/dylan/index.html): Several improvements and fixes.
+
+## 5.12.0 (2016-02-19)
+
+### New features
+
+[Vim bindings](http://codemirror.net/demo/vim.html): Ctrl-Q is now an alias for Ctrl-V.
+
+[Vim bindings](http://codemirror.net/demo/vim.html): The Vim API now exposes an `unmap` method to unmap bindings.
+
+[active-line addon](http://codemirror.net/demo/activeline.html): This addon can now style the active line's gutter.
+
+[FCL mode](http://codemirror.net/mode/fcl/): Newly added.
+
+[SQL mode](http://codemirror.net/mode/sql/): Now has a Postgresql dialect.
+
+### Bugfixes
+
+Fix [issue](https://github.com/codemirror/CodeMirror/issues/3781) where trying to scroll to a horizontal position outside of the document's width could cause the gutter to be positioned incorrectly.
+
+Use absolute, rather than fixed positioning in the context-menu intercept hack, to work around a [problem](https://github.com/codemirror/CodeMirror/issues/3238) when the editor is inside a transformed parent container.
+
+Solve a [problem](https://github.com/codemirror/CodeMirror/issues/3821) where the horizontal scrollbar could hide text in Firefox.
+
+Fix a [bug](https://github.com/codemirror/CodeMirror/issues/3834) that caused phantom scroll space under the text in some situations.
+
+[Sublime Text bindings](http://codemirror.net/demo/sublime.html): Bind delete-line to Shift-Ctrl-K on OS X.
+
+[Markdown mode](http://codemirror.net/mode/markdown/): Fix [issue](https://github.com/codemirror/CodeMirror/issues/3787) where the mode would keep state related to fenced code blocks in an unsafe way, leading to occasional corrupted parses.
+
+[Markdown mode](http://codemirror.net/mode/markdown/): Ignore backslashes in code fragments.
+
+[Markdown mode](http://codemirror.net/mode/markdown/): Use whichever mode is registered as `text/html` to parse HTML.
+
+[Clike mode](http://codemirror.net/mode/clike/): Improve indentation of Scala `=>` functions.
+
+[Python mode](http://codemirror.net/mode/python/): Improve indentation of bracketed code.
+
+[HTMLMixed mode](http://codemirror.net/mode/htmlmixed/): Support multi-line opening tags for sub-languages (`<script>`, `<style>`, etc).
+
+[Spreadsheet mode](http://codemirror.net/mode/spreadsheet/): Fix bug where the mode did not advance the stream when finding a backslash.
+
+[XML mode](http://codemirror.net/mode/xml/): The mode now takes a `matchClosing` option to configure whether mismatched closing tags should be highlighted as errors.
+
+## 5.11.0 (2016-01-20)
+
+* New modes: [JSX](http://codemirror.net/mode/jsx/index.html), [literate Haskell](http://codemirror.net/mode/haskell-literate/index.html)
+* The editor now forwards more [DOM events](http://codemirror.net/doc/manual.html#event_dom): `cut`, `copy`, `paste`, and `touchstart`. It will also forward `mousedown` for drag events
+* Fixes a bug where bookmarks next to collapsed spans were not rendered
+* The [Swift](http://codemirror.net/mode/swift/index.html) mode now supports auto-indentation
+* Frontmatters in the [YAML frontmatter](http://codemirror.net/mode/yaml-frontmatter/index.html) mode are now optional as intended
+
+## 5.10.0 (2015-12-21)
+
+* Modify the way [atomic ranges](http://codemirror.net/doc/manual.html#mark_atomic) are skipped by selection to try and make it less surprising.
+* The [Swift mode](http://codemirror.net/mode/swift/index.html) was rewritten.
+* New addon: [jump-to-line](http://codemirror.net/doc/manual.html#addon_jump-to-line).
+* New method: [`isReadOnly`](http://codemirror.net/doc/manual.html#isReadOnly).
+* The [show-hint addon](http://codemirror.net/doc/manual.html#addon_show-hint) now defaults to picking completions on single click.
+* The object passed to [`"beforeSelectionChange"`](http://codemirror.net/doc/manual.html#event_beforeSelectionChange) events now has an `origin` property.
+* New mode: [Crystal](http://codemirror.net/mode/crystal/index.html).
+
+## 5.9.0 (2015-11-23)
+
+* Improve the way overlay (OS X-style) scrollbars are handled
+* Make [annotatescrollbar](http://codemirror.net/doc/manual.html#addon_annotatescrollbar) and scrollpastend addons work properly together
+* Make [show-hint](http://codemirror.net/doc/manual.html#addon_show-hint) addon select options on single click by default, move selection to hovered item
+* Properly fold comments that include block-comment-start markers
+* Many small language mode fixes
+
+## 5.8.0 (2015-10-20)
+
+* Fixes an infinite loop in the [hardwrap addon](http://codemirror.net/doc/manual.html#addon_hardwrap)
+* New modes: [NSIS](http://codemirror.net/mode/nsis/index.html), [Ceylon](http://codemirror.net/mode/clike/index.html)
+* The Kotlin mode is now a [clike](http://codemirror.net/mode/clike/index.html) dialect, rather than a stand-alone mode
+* New option: [`allowDropFileTypes`](http://codemirror.net/doc/manual.html#option_allowDropFileTypes). Binary files can no longer be dropped into CodeMirror
+* New themes: [bespin](http://codemirror.net/demo/theme.html#bespin), [hopscotch](http://codemirror.net/demo/theme.html#hopscotch), [isotope](http://codemirror.net/demo/theme.html#isotope), [railscasts](http://codemirror.net/demo/theme.html#railscasts)
+
+## 5.7.0 (2015-09-21)
+
+* New modes: [Vue](http://codemirror.net/mode/vue/index.html), [Oz](http://codemirror.net/mode/oz/index.html), [MscGen](http://codemirror.net/mode/mscgen/index.html) (and dialects), [Closure Stylesheets](http://codemirror.net/mode/css/gss.html)
+* Implement [CommonMark](http://commonmark.org)-style flexible list indent and cross-line code spans in [Markdown](http://codemirror.net/mode/markdown/index.html) mode
+* Add a replace-all button to the [search addon](http://codemirror.net/doc/manual.html#addon_search), and make the persistent search dialog transparent when it obscures the match
+* Handle `acync`/`await` and ocal and binary numbers in [JavaScript mode](http://codemirror.net/mode/javascript/index.html)
+* Fix various issues with the [Haxe mode](http://codemirror.net/mode/haxe/index.html)
+* Make the [closebrackets addon](http://codemirror.net/doc/manual.html#addon_closebrackets) select only the wrapped text when wrapping selection in brackets
+* Tokenize properties as properties in the [CoffeeScript mode](http://codemirror.net/mode/coffeescript/index.html)
+* The [placeholder addon](http://codemirror.net/doc/manual.html#addon_placeholder) now accepts a DOM node as well as a string placeholder
+
+## 5.6.0 (2015-08-20)
+
+* Fix bug where you could paste into a `readOnly` editor
+* Show a cursor at the drop location when dragging over the editor
+* The [Rust mode](http://codemirror.net/mode/rust/index.html) was rewritten to handle modern Rust
+* The editor and theme CSS was cleaned up. Some selectors are now less specific than before
+* New theme: [abcdef](http://codemirror.net/demo/theme.html#abcdef)
+* Lines longer than [`maxHighlightLength`](http://codemirror.net/doc/manual.html#option_maxHighlightLength) are now less likely to mess up indentation
+* New addons: [`autorefresh`](http://codemirror.net/doc/manual.html#addon_autorefresh) for refreshing an editor the first time it becomes visible, and `html-lint` for using [HTMLHint](http://htmlhint.com/)
+* The [`search`](http://codemirror.net/doc/manual.html#addon_search) addon now recognizes `\r` and `\n` in pattern and replacement input
+
+## 5.5.0 (2015-07-20)
+
+*   New option: [`lineSeparator`](http://codemirror.net/doc/manual.html#option_lineSeparator) (with corresponding [method](http://codemirror.net/doc/manual.html#lineSeparator))
+*   New themes: [dracula](http://codemirror.net/demo/theme.html#dracula), [seti](http://codemirror.net/demo/theme.html#seti), [yeti](http://codemirror.net/demo/theme.html#yeti), [material](http://codemirror.net/demo/theme.html#material), and [icecoder](http://codemirror.net/demo/theme.html#icecoder)
+*   New modes: [Brainfuck](http://codemirror.net/mode/brainfuck/index.html), [VHDL](http://codemirror.net/mode/vhdl/index.html), Squirrel ([clike](http://codemirror.net/mode/clike/index.html) dialect)
+*   Define a `findPersistent` command in the [search](http://codemirror.net/demo/search.html) addon, for a dialog that stays open as you cycle through matches
+*   From this release on, the NPM module doesn't include documentation and demos
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/5.4.0...5.5.0)
+
+## 5.4.0 (2015-06-25)
+
+*   New modes: [Twig](http://codemirror.net/mode/twig/index.html), [Elm](http://codemirror.net/mode/elm/index.html), [Factor](http://codemirror.net/mode/factor/index.html), [Swift](http://codemirror.net/mode/swift/index.html)
+*   Prefer clipboard API (if available) when pasting
+*   Refined definition highlighting in [clike](http://codemirror.net/mode/clike/index.html) mode
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/5.3.0...5.4.0)
+
+## 5.3.0 (2015-05-20)
+
+*   Fix several regressions in the [`show-hint`](http://codemirror.net/doc/manual.html#addon_show-hint) addon (`completeSingle` option, `"shown"` and `"close"` events)
+*   The [vim mode](http://codemirror.net/demo/vim.html) API was [documented](http://codemirror.net/doc/manual.html#vimapi)
+*   New modes: [ASN.1](http://codemirror.net/mode/asn.1/index.html), [TTCN](http://codemirror.net/mode/ttcn/index.html), and [TTCN-CFG](http://codemirror.net/mode/ttcn-cfg/index.html)
+*   The [clike](http://codemirror.net/mode/clike/index.html) mode can now deep-indent `switch` statements, and roughly recognizes types and defined identifiers
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/5.2.0...5.3.0)
+
+## 5.2.0 (2015-04-20)
+
+*   Fix several race conditions in [`show-hint`](http://codemirror.net/doc/manual.html#addon_show-hint)'s asynchronous mode
+*   Fix backspace binding in [Sublime bindings](http://codemirror.net/demo/sublime.html)
+*   Change the way IME is handled in the `"textarea"` [input style](http://codemirror.net/doc/manual.html#option_inputStyle)
+*   New modes: [MUMPS](http://codemirror.net/mode/mumps/index.html), [Handlebars](http://codemirror.net/mode/handlebars/index.html)
+*   Rewritten modes: [Django](http://codemirror.net/mode/django/index.html), [Z80](http://codemirror.net/mode/z80/index.html)
+*   New theme: [Liquibyte](http://codemirror.net/demo/theme.html#liquibyte)
+*   New option: [`lineWiseCopyCut`](http://codemirror.net/doc/manual.html#option_lineWiseCopyCut)
+*   The [Vim mode](http://codemirror.net/demo/vim.html) now supports buffer-local options and the `filetype` setting
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/5.1.0...5.2.0)
+
+## 5.1.0 (2015-03-23)
+
+*   New modes: [ASCII armor](http://codemirror.net/mode/asciiarmor/index.html) (PGP data), [Troff](http://codemirror.net/mode/troff/index.html), and [CMake](http://codemirror.net/mode/cmake/index.html).
+*   Remove SmartyMixed mode, rewrite [Smarty](http://codemirror.net/mode/smarty/index.html) mode to supersede it.
+*   New commands in the [merge addon](http://codemirror.net/doc/manual.html#addon_merge): `goNextDiff` and `goPrevDiff`.
+*   The [closebrackets addon](http://codemirror.net/doc/manual.html#addon_closebrackets) can now be configured per mode.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/5.0.0...5.1.0).
+
+## 5.0.0 (2015-02-20)
+
+*   Experimental mobile support (tested on iOS, Android Chrome, stock Android browser)
+*   New option [`inputStyle`](http://codemirror.net/doc/manual.html#option_inputStyle) to switch between hidden textarea and contenteditable input.
+*   The [`getInputField`](http://codemirror.net/doc/manual.html#getInputField) method is no longer guaranteed to return a textarea.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.13.0...5.0.0).
+
+## 4.13.0 (2015-02-20)
+
+*   Fix the way the [`closetag`](http://codemirror.net/demo/closetag.html) demo handles the slash character.
+*   New modes: [Forth](http://codemirror.net/mode/forth/index.html), [Stylus](http://codemirror.net/mode/stylus/index.html).
+*   Make the [CSS mode](http://codemirror.net/mode/css/index.html) understand some modern CSS extensions.
+*   Have the [Scala mode](http://codemirror.net/mode/clike/index.html) handle symbols and triple-quoted strings.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.12.0...4.13.0).
+
+## 4.12.0 (2015-01-22)
+
+*   The [`closetag`](http://codemirror.net/doc/manual.html#addon_closetag) addon now defines a `"closeTag"` command.
+*   Adds a `findModeByFileName` to the [mode metadata](http://codemirror.net/doc/manual.html#addon_meta) addon.
+*   [Simple mode](http://codemirror.net/demo/simplemode.html) rules can now contain a `sol` property to only match at the start of a line.
+*   New addon: [`selection-pointer`](http://codemirror.net/doc/manual.html#addon_selection-pointer) to style the mouse cursor over the selection.
+*   Improvements to the [Sass mode](http://codemirror.net/mode/sass/index.html)'s indentation.
+*   The [Vim keymap](http://codemirror.net/demo/vim.html)'s search functionality now supports [scrollbar annotation](http://codemirror.net/doc/manual.html#addon_matchesonscrollbar).
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.11.0...4.12.0).
+
+## 4.11.0 (2015-01-09)
+
+Unfortunately, 4.10 did not take care of the Firefox scrolling issue entirely. This release adds two more patches to address that.
+
+## 4.10.0 (2014-12-29)
+
+Emergency single-patch update to 4.9\. Fixes Firefox-specific problem where the cursor could end up behind the horizontal scrollbar.
+
+## 4.9.0 (2014-12-23)
+
+*   Overhauled scroll bar handling. Add pluggable [scrollbar implementations](http://codemirror.net/demo/simplescrollbars.html).
+*   Tweaked behavior for the [completion addons](http://codemirror.net/doc/manual.html#addon_show-hint) to not take text after cursor into account.
+*   Two new optional features in the [merge addon](http://codemirror.net/doc/manual.html#addon_merge): aligning editors, and folding unchanged text.
+*   New modes: [Dart](http://codemirror.net/mode/dart/index.html), [EBNF](http://codemirror.net/mode/ebnf/index.html), [spreadsheet](http://codemirror.net/mode/spreadsheet/index.html), and [Soy](http://codemirror.net/mode/soy/index.html).
+*   New [addon](http://codemirror.net/demo/panel.html) to show persistent panels below/above an editor.
+*   New themes: [zenburn](http://codemirror.net/demo/theme.html#zenburn) and [tomorrow night bright](http://codemirror.net/demo/theme.html#tomorrow-night-bright).
+*   Allow ctrl-click to clear existing cursors.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.8.0...4.9.0).
+
+## 4.8.0 (2014-11-22)
+
+*   Built-in support for [multi-stroke key bindings](http://codemirror.net/doc/manual.html#normalizeKeyMap).
+*   New method: [`getLineTokens`](http://codemirror.net/doc/manual.html#getLineTokens).
+*   New modes: [dockerfile](http://codemirror.net/mode/dockerfile/index.html), [IDL](http://codemirror.net/mode/idl/index.html), [Objective C](http://codemirror.net/mode/clike/index.html) (crude).
+*   Support styling of gutter backgrounds, allow `"gutter"` styles in [`addLineClass`](http://codemirror.net/doc/manual.html#addLineClass).
+*   Many improvements to the [Vim mode](http://codemirror.net/demo/vim.html), rewritten visual mode.
+*   Improvements to modes: [gfm](http://codemirror.net/mode/gfm/index.html) (strikethrough), [SPARQL](http://codemirror.net/mode/sparql/index.html) (version 1.1 support), and [sTeX](http://codemirror.net/mode/stex/index.html) (no more runaway math mode).
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.7.0...4.8.0).
+
+## 4.7.0 (2014-10-20)
+
+*   **Incompatible**: The [lint addon](http://codemirror.net/demo/lint.html) now passes the editor's value as first argument to asynchronous lint functions, for consistency. The editor is still passed, as fourth argument.
+*   Improved handling of unicode identifiers in modes for languages that support them.
+*   More mode improvements: [CoffeeScript](http://codemirror.net/mode/coffeescript/index.html) (indentation), [Verilog](http://codemirror.net/mode/verilog/index.html) (indentation), [Scala](http://codemirror.net/mode/clike/index.html) (indentation, triple-quoted strings), and [PHP](http://codemirror.net/mode/php/index.html) (interpolated variables in heredoc strings).
+*   New modes: [Textile](http://codemirror.net/mode/textile/index.html) and [Tornado templates](http://codemirror.net/mode/tornado/index.html).
+*   Experimental new [way to define modes](http://codemirror.net/demo/simplemode.html).
+*   Improvements to the [Vim bindings](http://codemirror.net/demo/vim.html): Arbitrary insert mode key mappings are now possible, and text objects are supported in visual mode.
+*   The mode [meta-information file](http://codemirror.net/mode/meta.js) now includes information about file extensions, and [helper functions](http://codemirror.net/doc/manual.html#addon_meta) `findModeByMIME` and `findModeByExtension`.
+*   New logo!
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.6.0...4.7.0).
+
+## 4.6.0 (2014-09-19)
+
+*   New mode: [Modelica](http://codemirror.net/mode/modelica/index.html)
+*   New method: [`findWordAt`](http://codemirror.net/doc/manual.html#findWordAt)
+*   Make it easier to [use text background styling](http://codemirror.net/demo/markselection.html)
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.5.0...4.6.0).
+
+## 4.5.0 (2014-08-21)
+
+*   Fix several serious bugs with horizontal scrolling
+*   New mode: [Slim](http://codemirror.net/mode/slim/index.html)
+*   New command: [`goLineLeftSmart`](http://codemirror.net/doc/manual.html#command_goLineLeftSmart)
+*   More fixes and extensions for the [Vim](http://codemirror.net/demo/vim.html) visual block mode
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.4.0...4.5.0).
+
+## 4.4.0 (2014-07-21)
+
+*   **Note:** Some events might now fire in slightly different order (`"change"` is still guaranteed to fire before `"cursorActivity"`)
+*   Nested operations in multiple editors are now synced (complete at same time, reducing DOM reflows)
+*   Visual block mode for [vim](http://codemirror.net/demo/vim.html) (<C-v>) is nearly complete
+*   New mode: [Kotlin](http://codemirror.net/mode/kotlin/index.html)
+*   Better multi-selection paste for text copied from multiple CodeMirror selections
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.3.0...4.4.0).
+
+## 4.3.0 (2014-06-23)
+
+*   Several [vim bindings](http://codemirror.net/demo/vim.html) improvements: search and exCommand history, global flag for `:substitute`, `:global` command.
+*   Allow hiding the cursor by setting [`cursorBlinkRate`](http://codemirror.net/doc/manual.html#option_cursorBlinkRate) to a negative value.
+*   Make gutter markers themeable, use this in foldgutter.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.2.0...4.3.0).
+
+## 4.2.0 (2014-05-19)
+
+*   Fix problem where some modes were broken by the fact that empty tokens were forbidden.
+*   Several fixes to context menu handling.
+*   On undo, scroll _change_, not cursor, into view.
+*   Rewritten [Jade](http://codemirror.net/mode/jade/index.html) mode.
+*   Various improvements to [Shell](http://codemirror.net/mode/shell/index.html) (support for more syntax) and [Python](http://codemirror.net/mode/python/index.html) (better indentation) modes.
+*   New mode: [Cypher](http://codemirror.net/mode/cypher/index.html).
+*   New theme: [Neo](http://codemirror.net/demo/theme.html#neo).
+*   Support direct styling options (color, line style, width) in the [rulers](http://codemirror.net/doc/manual.html#addon_rulers) addon.
+*   Recognize per-editor configuration for the [show-hint](http://codemirror.net/doc/manual.html#addon_show-hint) and [foldcode](http://codemirror.net/doc/manual.html#addon_foldcode) addons.
+*   More intelligent scanning for existing close tags in [closetag](http://codemirror.net/doc/manual.html#addon_closetag) addon.
+*   In the [Vim bindings](http://codemirror.net/demo/vim.html): Fix bracket matching, support case conversion in visual mode, visual paste, append action.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.1.0...4.2.0).
+
+## 4.1.0 (2014-04-22)
+
+*   _Slightly incompatible_: The [`"cursorActivity"`](http://codemirror.net/doc/manual.html#event_cursorActivity) event now fires after all other events for the operation (and only for handlers that were actually registered at the time the activity happened).
+*   New command: [`insertSoftTab`](http://codemirror.net/doc/manual.html#command_insertSoftTab).
+*   New mode: [Django](http://codemirror.net/mode/django/index.html).
+*   Improved modes: [Verilog](http://codemirror.net/mode/verilog/index.html) (rewritten), [Jinja2](http://codemirror.net/mode/jinja2/index.html), [Haxe](http://codemirror.net/mode/haxe/index.html), [PHP](http://codemirror.net/mode/php/index.html) (string interpolation highlighted), [JavaScript](http://codemirror.net/mode/javascript/index.html) (indentation of trailing else, template strings), [LiveScript](http://codemirror.net/mode/livescript/index.html) (multi-line strings).
+*   Many small issues from the 3.x→4.x transition were found and fixed.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.0.3...4.1.0).
+
+## 3.24.0 (2014-04-22)
+
+Merges the improvements from 4.1 that could easily be applied to the 3.x code. Also improves the way the editor size is updated when line widgets change.
+
+## 3.23.0 (2014-03-20)
+
+*   In the [XML mode](http://codemirror.net/mode/xml/index.html), add `brackets` style to angle brackets, fix case-sensitivity of tags for HTML.
+*   New mode: [Dylan](http://codemirror.net/mode/dylan/index.html).
+*   Many improvements to the [Vim bindings](http://codemirror.net/demo/vim.html).
+
+## 3.22.0 (2014-02-21)
+
+*   Adds the [`findMarks`](http://codemirror.net/doc/manual.html#findMarks) method.
+*   New addons: [rulers](http://codemirror.net/doc/manual.html#addon_rulers), markdown-fold, yaml-lint.
+*   New theme: [mdn-like](http://codemirror.net/demo/theme.html#mdn-like).
+*   New mode: [Solr](http://codemirror.net/mode/solr/index.html).
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.21.0...3.22.0).
+
+## 3.21.0 (2014-01-16)
+
+*   Auto-indenting a block will no longer add trailing whitespace to blank lines.
+*   Marking text has a new option [`clearWhenEmpty`](http://codemirror.net/doc/manual.html#markText) to control auto-removal.
+*   Several bugfixes in the handling of bidirectional text.
+*   The [XML](http://codemirror.net/mode/xml/index.html) and [CSS](http://codemirror.net/mode/css/index.html) modes were largely rewritten. [LESS](http://codemirror.net/mode/css/less.html) support was added to the CSS mode.
+*   The OCaml mode was moved to an [mllike](http://codemirror.net/mode/mllike/index.html) mode, F# support added.
+*   Make it possible to fetch multiple applicable helper values with [`getHelpers`](http://codemirror.net/doc/manual.html#getHelpers), and to register helpers matched on predicates with [`registerGlobalHelper`](http://codemirror.net/doc/manual.html#registerGlobalHelper).
+*   New theme [pastel-on-dark](http://codemirror.net/demo/theme.html#pastel-on-dark).
+*   Better ECMAScript 6 support in [JavaScript](http://codemirror.net/mode/javascript/index.html) mode.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.20.0...3.21.0).
+
+## 3.20.0 (2013-11-21)
+
+*   New modes: [Julia](http://codemirror.net/mode/julia/index.html) and [PEG.js](http://codemirror.net/mode/pegjs/index.html).
+*   Support ECMAScript 6 in the [JavaScript mode](http://codemirror.net/mode/javascript/index.html).
+*   Improved indentation for the [CoffeeScript mode](http://codemirror.net/mode/coffeescript/index.html).
+*   Make non-printable-character representation [configurable](http://codemirror.net/doc/manual.html#option_specialChars).
+*   Add ‘notification’ functionality to [dialog](http://codemirror.net/doc/manual.html#addon_dialog) addon.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.19.0...3.20.0).
+
+## 3.19.0 (2013-10-21)
+
+*   New modes: [Eiffel](http://codemirror.net/mode/eiffel/index.html), [Gherkin](http://codemirror.net/mode/gherkin/index.html), [MSSQL dialect](http://codemirror.net/mode/sql/?mime=text/x-mssql).
+*   New addons: [hardwrap](http://codemirror.net/doc/manual.html#addon_hardwrap), [sql-hint](http://codemirror.net/doc/manual.html#addon_sql-hint).
+*   New theme: [MBO](http://codemirror.net/demo/theme.html#mbo).
+*   Add [support](http://codemirror.net/doc/manual.html#token_style_line) for line-level styling from mode tokenizers.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.18.0...3.19.0).
+
+## 3.18.0 (2013-09-23)
+
+Emergency release to fix a problem in 3.17 where `.setOption("lineNumbers", false)` would raise an error.
+
+## 3.17.0 (2013-09-23)
+
+*   New modes: [Fortran](http://codemirror.net/mode/fortran/index.html), [Octave](http://codemirror.net/mode/octave/index.html) (Matlab), [TOML](http://codemirror.net/mode/toml/index.html), and [DTD](http://codemirror.net/mode/dtd/index.html).
+*   New addons: [`css-lint`](http://codemirror.net/addon/lint/css-lint.js), [`css-hint`](http://codemirror.net/doc/manual.html#addon_css-hint).
+*   Improve resilience to CSS 'frameworks' that globally mess up `box-sizing`.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.16.0...3.17.0).
+
+## 3.16.0 (2013-08-21)
+
+*   The whole codebase is now under a single [license](http://codemirror.net/LICENSE) file.
+*   The project page was overhauled and redesigned.
+*   New themes: [Paraiso](http://codemirror.net/demo/theme.html#paraiso-dark) ([light](http://codemirror.net/demo/theme.html#paraiso-light)), [The Matrix](http://codemirror.net/demo/theme.html#the-matrix).
+*   Improved interaction between themes and [active-line](http://codemirror.net/doc/manual.html#addon_active-line)/[matchbrackets](http://codemirror.net/doc/manual.html#addon_matchbrackets) addons.
+*   New [folding](http://codemirror.net/doc/manual.html#addon_foldcode) function `CodeMirror.fold.comment`.
+*   Added [fullscreen](http://codemirror.net/doc/manual.html#addon_fullscreen) addon.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.15.0...3.16.0).
+
+## 3.15.0 (2013-07-29)
+
+*   New modes: [Jade](http://codemirror.net/mode/jade/index.html), [Nginx](http://codemirror.net/mode/nginx/index.html).
+*   New addons: [Tern](http://codemirror.net/demo/tern.html), [matchtags](http://codemirror.net/doc/manual.html#addon_matchtags), and [foldgutter](http://codemirror.net/doc/manual.html#addon_foldgutter).
+*   Introduced [_helper_](http://codemirror.net/doc/manual.html#getHelper) concept ([context](https://groups.google.com/forum/#!msg/codemirror/cOc0xvUUEUU/nLrX1-qnidgJ)).
+*   New method: [`getModeAt`](http://codemirror.net/doc/manual.html#getModeAt).
+*   New themes: base16 [dark](http://codemirror.net/demo/theme.html#base16-dark)/[light](http://codemirror.net/demo/theme.html#base16-light), 3024 [dark](http://codemirror.net/demo/theme.html#3024-night)/[light](http://codemirror.net/demo/theme.html#3024-day), [tomorrow-night](http://codemirror.net/demo/theme.html#tomorrow-night-eighties).
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.14.0...3.15.0).
+
+## 3.14.0 (2013-06-20)
+
+*   New addons: [trailing space highlight](http://codemirror.net/doc/manual.html#addon_trailingspace), [XML completion](http://codemirror.net/doc/manual.html#addon_xml-hint) (rewritten), and [diff merging](http://codemirror.net/doc/manual.html#addon_merge).
+*   [`markText`](http://codemirror.net/doc/manual.html#markText) and [`addLineWidget`](http://codemirror.net/doc/manual.html#addLineWidget) now take a `handleMouseEvents` option.
+*   New methods: [`lineAtHeight`](http://codemirror.net/doc/manual.html#lineAtHeight), [`getTokenTypeAt`](http://codemirror.net/doc/manual.html#getTokenTypeAt).
+*   More precise cleanness-tracking using [`changeGeneration`](http://codemirror.net/doc/manual.html#changeGeneration) and [`isClean`](http://codemirror.net/doc/manual.html#isClean).
+*   Many extensions to [Emacs](http://codemirror.net/demo/emacs.html) mode (prefixes, more navigation units, and more).
+*   New events [`"keyHandled"`](http://codemirror.net/doc/manual.html#event_keyHandled) and [`"inputRead"`](http://codemirror.net/doc/manual.html#event_inputRead).
+*   Various improvements to [Ruby](http://codemirror.net/mode/ruby/index.html), [Smarty](http://codemirror.net/mode/smarty/index.html), [SQL](http://codemirror.net/mode/sql/index.html), and [Vim](http://codemirror.net/demo/vim.html) modes.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.13.0...3.14.0).
+
+## 3.13.0 (2013-05-20)
+
+*   New modes: [COBOL](http://codemirror.net/mode/cobol/index.html) and [HAML](http://codemirror.net/mode/haml/index.html).
+*   New options: [`cursorScrollMargin`](http://codemirror.net/doc/manual.html#option_cursorScrollMargin) and [`coverGutterNextToScrollbar`](http://codemirror.net/doc/manual.html#option_coverGutterNextToScrollbar).
+*   New addon: [commenting](http://codemirror.net/doc/manual.html#addon_comment).
+*   More features added to the [Vim keymap](http://codemirror.net/demo/vim.html).
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v3.12...3.13.0).
+
+## 3.12.0 (2013-04-19)
+
+*   New mode: [GNU assembler](http://codemirror.net/mode/gas/index.html).
+*   New options: [`maxHighlightLength`](http://codemirror.net/doc/manual.html#option_maxHighlightLength) and [`historyEventDelay`](http://codemirror.net/doc/manual.html#option_historyEventDelay).
+*   Added [`addToHistory`](http://codemirror.net/doc/manual.html#mark_addToHistory) option for `markText`.
+*   Various fixes to JavaScript tokenization and indentation corner cases.
+*   Further improvements to the vim mode.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v3.11...v3.12).
+
+## 3.11.0 (2013-03-20)
+
+*   **Removed code:** `collapserange`, `formatting`, and `simple-hint` addons. `plsql` and `mysql` modes (use [`sql`](http://codemirror.net/mode/sql/index.html) mode).
+*   **Moved code:** the range-finding functions for folding now have [their own files](http://codemirror.net/addon/fold/).
+*   **Changed interface:** the [`continuecomment`](http://codemirror.net/doc/manual.html#addon_continuecomment) addon now exposes an option, rather than a command.
+*   New modes: [SCSS](http://codemirror.net/mode/css/scss.html), [Tcl](http://codemirror.net/mode/tcl/index.html), [LiveScript](http://codemirror.net/mode/livescript/index.html), and [mIRC](http://codemirror.net/mode/mirc/index.html).
+*   New addons: [`placeholder`](http://codemirror.net/demo/placeholder.html), [HTML completion](http://codemirror.net/demo/html5complete.html).
+*   New methods: [`hasFocus`](http://codemirror.net/doc/manual.html#hasFocus), [`defaultCharWidth`](http://codemirror.net/doc/manual.html#defaultCharWidth).
+*   New events: [`beforeCursorEnter`](http://codemirror.net/doc/manual.html#event_beforeCursorEnter), [`renderLine`](http://codemirror.net/doc/manual.html#event_renderLine).
+*   Many improvements to the [`show-hint`](http://codemirror.net/doc/manual.html#addon_show-hint) completion dialog addon.
+*   Tweak behavior of by-word cursor motion.
+*   Further improvements to the [vim mode](http://codemirror.net/demo/vim.html).
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v3.1...v3.11).
+
+## 3.02.0 (2013-01-25)
+
+Single-bugfix release. Fixes a problem that prevents CodeMirror instances from being garbage-collected after they become unused.
+
+## 3.01.0 (2013-01-21)
+
+*   Move all add-ons into an organized directory structure under [`/addon`](http://codemirror.net/addon/). **You might have to adjust your paths.**
+*   New modes: [D](http://codemirror.net/mode/d/index.html), [Sass](http://codemirror.net/mode/sass/index.html), [APL](http://codemirror.net/mode/apl/index.html), [SQL](http://codemirror.net/mode/sql/index.html) (configurable), and [Asterisk](http://codemirror.net/mode/asterisk/index.html).
+*   Several bugfixes in right-to-left text support.
+*   Add [`rtlMoveVisually`](http://codemirror.net/doc/manual.html#option_rtlMoveVisually) option.
+*   Improvements to vim keymap.
+*   Add built-in (lightweight) [overlay mode](http://codemirror.net/doc/manual.html#addOverlay) support.
+*   Support `showIfHidden` option for [line widgets](http://codemirror.net/doc/manual.html#addLineWidget).
+*   Add simple [Python hinter](http://codemirror.net/doc/manual.html#addon_python-hint).
+*   Bring back the [`fixedGutter`](http://codemirror.net/doc/manual.html#option_fixedGutter) option.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v3.0...v3.01).
+
+## 3.1.0 (2013-02-21)
+
+*   **Incompatible:** key handlers may now _return_, rather than _throw_ `CodeMirror.Pass` to signal they didn't handle the key.
+*   Make documents a [first-class construct](http://codemirror.net/doc/manual.html#api_doc), support split views and subviews.
+*   Add a [new module](http://codemirror.net/doc/manual.html#addon_show-hint) for showing completion hints. Deprecate `simple-hint.js`.
+*   Extend [htmlmixed mode](http://codemirror.net/mode/htmlmixed/index.html) to allow custom handling of script types.
+*   Support an `insertLeft` option to [`setBookmark`](http://codemirror.net/doc/manual.html#setBookmark).
+*   Add an [`eachLine`](http://codemirror.net/doc/manual.html#eachLine) method to iterate over a document.
+*   New addon modules: [selection marking](http://codemirror.net/demo/markselection.html), [linting](http://codemirror.net/demo/lint.html), and [automatic bracket closing](http://codemirror.net/demo/closebrackets.html).
+*   Add [`"beforeChange"`](http://codemirror.net/doc/manual.html#event_beforeChange) and [`"beforeSelectionChange"`](http://codemirror.net/doc/manual.html#event_beforeSelectionChange) events.
+*   Add [`"hide"`](http://codemirror.net/doc/manual.html#event_hide) and [`"unhide"`](http://codemirror.net/doc/manual.html#event_unhide) events to marked ranges.
+*   Fix [`coordsChar`](http://codemirror.net/doc/manual.html#coordsChar)'s interpretation of its argument to match the documentation.
+*   New modes: [Turtle](http://codemirror.net/mode/turtle/index.html) and [Q](http://codemirror.net/mode/q/index.html).
+*   Further improvements to the [vim mode](http://codemirror.net/demo/vim.html).
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v3.01...v3.1).
+
+## 3.0.0 (2012-12-10)
+
+**New major version**. Only partially backwards-compatible. See the [upgrading guide](http://codemirror.net/doc/upgrade_v3.html) for more information. Changes since release candidate 2:
+
+*   Rewritten VIM mode.
+*   Fix a few minor scrolling and sizing issues.
+*   Work around Safari segfault when dragging.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v3.0rc2...v3.0).
+
+## 2.38.0 (2013-01-21)
+
+Integrate some bugfixes, enhancements to the vim keymap, and new modes ([D](http://codemirror.net/mode/d/index.html), [Sass](http://codemirror.net/mode/sass/index.html), [APL](http://codemirror.net/mode/apl/index.html)) from the v3 branch.
+
+## 2.37.0 (2012-12-20)
+
+*   New mode: [SQL](http://codemirror.net/mode/sql/index.html) (will replace [plsql](http://codemirror.net/mode/plsql/index.html) and [mysql](http://codemirror.net/mode/mysql/index.html) modes).
+*   Further work on the new VIM mode.
+*   Fix Cmd/Ctrl keys on recent Operas on OS X.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v2.36...v2.37).
+
+## 2.36.0 (2012-11-20)
+
+*   New mode: [Z80 assembly](http://codemirror.net/mode/z80/index.html).
+*   New theme: [Twilight](http://codemirror.net/demo/theme.html#twilight).
+*   Add command-line compression helper.
+*   Make [`scrollIntoView`](http://codemirror.net/doc/manual.html#scrollIntoView) public.
+*   Add [`defaultTextHeight`](http://codemirror.net/doc/manual.html#defaultTextHeight) method.
+*   Various extensions to the vim keymap.
+*   Make [PHP mode](http://codemirror.net/mode/php/index.html) build on [mixed HTML mode](http://codemirror.net/mode/htmlmixed/index.html).
+*   Add [comment-continuing](http://codemirror.net/doc/manual.html#addon_continuecomment) add-on.
+*   Full [list of patches](http://codemirror.net/https://github.com/codemirror/CodeMirror/compare/v2.35...v2.36).
+
+## 2.35.0 (2012-10-22)
+
+*   New (sub) mode: [TypeScript](http://codemirror.net/mode/javascript/typescript.html).
+*   Don't overwrite (insert key) when pasting.
+*   Fix several bugs in [`markText`](http://codemirror.net/doc/manual.html#markText)/undo interaction.
+*   Better indentation of JavaScript code without semicolons.
+*   Add [`defineInitHook`](http://codemirror.net/doc/manual.html#defineInitHook) function.
+*   Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v2.34...v2.35).
+
+## 2.34.0 (2012-09-19)
+
+*   New mode: [Common Lisp](http://codemirror.net/mode/commonlisp/index.html).
+*   Fix right-click select-all on most browsers.
+*   Change the way highlighting happens:
+      Saves memory and CPU cycles.
+      `compareStates` is no longer needed.
+      `onHighlightComplete` no longer works.
+*   Integrate mode (Markdown, XQuery, CSS, sTex) tests in central testsuite.
+*   Add a [`CodeMirror.version`](http://codemirror.net/doc/manual.html#version) property.
+*   More robust handling of nested modes in [formatting](http://codemirror.net/demo/formatting.html) and [closetag](http://codemirror.net/demo/closetag.html) plug-ins.
+*   Un/redo now preserves [marked text](http://codemirror.net/doc/manual.html#markText) and bookmarks.
+*   [Full list](https://github.com/codemirror/CodeMirror/compare/v2.33...v2.34) of patches.
+
+## 2.33.0 (2012-08-23)
+
+*   New mode: [Sieve](http://codemirror.net/mode/sieve/index.html).
+*   New [`getViewPort`](http://codemirror.net/doc/manual.html#getViewport) and [`onViewportChange`](http://codemirror.net/doc/manual.html#option_onViewportChange) API.
+*   [Configurable](http://codemirror.net/doc/manual.html#option_cursorBlinkRate) cursor blink rate.
+*   Make binding a key to `false` disabling handling (again).
+*   Show non-printing characters as red dots.
+*   More tweaks to the scrolling model.
+*   Expanded testsuite. Basic linter added.
+*   Remove most uses of `innerHTML`. Remove `CodeMirror.htmlEscape`.
+*   [Full list](https://github.com/codemirror/CodeMirror/compare/v2.32...v2.33) of patches.
+
+## 2.32.0 (2012-07-23)
+
+Emergency fix for a bug where an editor with line wrapping on IE will break when there is _no_ scrollbar.
+
+## 2.31.0 (2012-07-20)
+
+*   New modes: [OCaml](http://codemirror.net/mode/ocaml/index.html), [Haxe](http://codemirror.net/mode/haxe/index.html), and [VB.NET](http://codemirror.net/mode/vb/index.html).
+*   Several fixes to the new scrolling model.
+*   Add a [`setSize`](http://codemirror.net/doc/manual.html#setSize) method for programmatic resizing.
+*   Add [`getHistory`](http://codemirror.net/doc/manual.html#getHistory) and [`setHistory`](http://codemirror.net/doc/manual.html#setHistory) methods.
+*   Allow custom line separator string in [`getValue`](http://codemirror.net/doc/manual.html#getValue) and [`getRange`](http://codemirror.net/doc/manual.html#getRange).
+*   Support double- and triple-click drag, double-clicking whitespace.
+*   And more... [(all patches)](https://github.com/codemirror/CodeMirror/compare/v2.3...v2.31)
+
+## 2.30.0 (2012-06-22)
+
+*   **New scrollbar implementation**. Should flicker less. Changes DOM structure of the editor.
+*   New theme: [vibrant-ink](http://codemirror.net/demo/theme.html#vibrant-ink).
+*   Many extensions to the VIM keymap (including text objects).
+*   Add [mode-multiplexing](http://codemirror.net/demo/multiplex.html) utility script.
+*   Fix bug where right-click paste works in read-only mode.
+*   Add a [`getScrollInfo`](http://codemirror.net/doc/manual.html#getScrollInfo) method.
+*   Lots of other [fixes](https://github.com/codemirror/CodeMirror/compare/v2.25...v2.3).
+
+## 2.25.0 (2012-05-23)
+
+*   New mode: [Erlang](http://codemirror.net/mode/erlang/index.html).
+*   **Remove xmlpure mode** (use [xml.js](http://codemirror.net/mode/xml/index.html)).
+*   Fix line-wrapping in Opera.
+*   Fix X Windows middle-click paste in Chrome.
+*   Fix bug that broke pasting of huge documents.
+*   Fix backspace and tab key repeat in Opera.
+
+## 2.24.0 (2012-04-23)
+
+*   **Drop support for Internet Explorer 6**.
+*   New modes: [Shell](http://codemirror.net/mode/shell/index.html), [Tiki wiki](http://codemirror.net/mode/tiki/index.html), [Pig Latin](http://codemirror.net/mode/pig/index.html).
+*   New themes: [Ambiance](http://codemirror.net/demo/theme.html#ambiance), [Blackboard](http://codemirror.net/demo/theme.html#blackboard).
+*   More control over drag/drop with [`dragDrop`](http://codemirror.net/doc/manual.html#option_dragDrop) and [`onDragEvent`](http://codemirror.net/doc/manual.html#option_onDragEvent) options.
+*   Make HTML mode a bit less pedantic.
+*   Add [`compoundChange`](http://codemirror.net/doc/manual.html#compoundChange) API method.
+*   Several fixes in undo history and line hiding.
+*   Remove (broken) support for `catchall` in key maps, add `nofallthrough` boolean field instead.
+
+## 2.23.0 (2012-03-26)
+
+*   Change **default binding for tab**. Starting in 2.23, these bindings are default:
+    *   Tab: Insert tab character
+    *   Shift-tab: Reset line indentation to default
+    *   Ctrl/Cmd-[: Reduce line indentation (old tab behaviour)
+    *   Ctrl/Cmd-]: Increase line indentation (old shift-tab behaviour)
+*   New modes: [XQuery](http://codemirror.net/mode/xquery/index.html) and [VBScript](http://codemirror.net/mode/vbscript/index.html).
+*   Two new themes: [lesser-dark](http://codemirror.net/mode/less/index.html) and [xq-dark](http://codemirror.net/mode/xquery/index.html).
+*   Differentiate between background and text styles in [`setLineClass`](http://codemirror.net/doc/manual.html#setLineClass).
+*   Fix drag-and-drop in IE9+.
+*   Extend [`charCoords`](http://codemirror.net/doc/manual.html#charCoords) and [`cursorCoords`](http://codemirror.net/doc/manual.html#cursorCoords) with a `mode` argument.
+*   Add [`autofocus`](http://codemirror.net/doc/manual.html#option_autofocus) option.
+*   Add [`findMarksAt`](http://codemirror.net/doc/manual.html#findMarksAt) method.
+
+## 2.22.0 (2012-02-27)
+
+*   Allow [key handlers](http://codemirror.net/doc/manual.html#keymaps) to pass up events, allow binding characters.
+*   Add [`autoClearEmptyLines`](http://codemirror.net/doc/manual.html#option_autoClearEmptyLines) option.
+*   Properly use tab stops when rendering tabs.
+*   Make PHP mode more robust.
+*   Support indentation blocks in [code folder](http://codemirror.net/doc/manual.html#addon_foldcode).
+*   Add a script for [highlighting instances of the selection](http://codemirror.net/doc/manual.html#addon_match-highlighter).
+*   New [.properties](http://codemirror.net/mode/properties/index.html) mode.
+*   Fix many bugs.
+
+## 2.21.0 (2012-01-27)
+
+*   Added [LESS](http://codemirror.net/mode/less/index.html), [MySQL](http://codemirror.net/mode/mysql/index.html), [Go](http://codemirror.net/mode/go/index.html), and [Verilog](http://codemirror.net/mode/verilog/index.html) modes.
+*   Add [`smartIndent`](http://codemirror.net/doc/manual.html#option_smartIndent) option.
+*   Support a cursor in [`readOnly`](http://codemirror.net/doc/manual.html#option_readOnly)-mode.
+*   Support assigning multiple styles to a token.
+*   Use a new approach to drawing the selection.
+*   Add [`scrollTo`](http://codemirror.net/doc/manual.html#scrollTo) method.
+*   Allow undo/redo events to span non-adjacent lines.
+*   Lots and lots of bugfixes.
+
+## 2.20.0 (2011-12-20)
+
+*   Slightly incompatible API changes. Read [this](http://codemirror.net/doc/upgrade_v2.2.html).
+*   New approach to [binding](http://codemirror.net/doc/manual.html#option_extraKeys) keys, support for [custom bindings](http://codemirror.net/doc/manual.html#option_keyMap).
+*   Support for overwrite (insert).
+*   [Custom-width](http://codemirror.net/doc/manual.html#option_tabSize) and [stylable](http://codemirror.net/demo/visibletabs.html) tabs.
+*   Moved more code into [add-on scripts](http://codemirror.net/doc/manual.html#addons).
+*   Support for sane vertical cursor movement in wrapped lines.
+*   More reliable handling of editing [marked text](http://codemirror.net/doc/manual.html#markText).
+*   Add minimal [emacs](http://codemirror.net/demo/emacs.html) and [vim](http://codemirror.net/demo/vim.html) bindings.
+*   Rename `coordsFromIndex` to [`posFromIndex`](http://codemirror.net/doc/manual.html#posFromIndex), add [`indexFromPos`](http://codemirror.net/doc/manual.html#indexFromPos) method.
+
+## 2.18.0 (2011-11-21)
+
+Fixes `TextMarker.clear`, which is broken in 2.17.
+
+## 2.17.0 (2011-11-21)
+
+*   Add support for [line wrapping](http://codemirror.net/doc/manual.html#option_lineWrapping) and [code folding](http://codemirror.net/doc/manual.html#hideLine).
+*   Add [Github-style Markdown](http://codemirror.net/mode/gfm/index.html) mode.
+*   Add [Monokai](http://codemirror.net/theme/monokai.css) and [Rubyblue](http://codemirror.net/theme/rubyblue.css) themes.
+*   Add [`setBookmark`](http://codemirror.net/doc/manual.html#setBookmark) method.
+*   Move some of the demo code into reusable components under [`lib/util`](http://codemirror.net/addon/).
+*   Make screen-coord-finding code faster and more reliable.
+*   Fix drag-and-drop in Firefox.
+*   Improve support for IME.
+*   Speed up content rendering.
+*   Fix browser's built-in search in Webkit.
+*   Make double- and triple-click work in IE.
+*   Various fixes to modes.
+
+## 2.16.0 (2011-10-27)
+
+*   Add [Perl](http://codemirror.net/mode/perl/index.html), [Rust](http://codemirror.net/mode/rust/index.html), [TiddlyWiki](http://codemirror.net/mode/tiddlywiki/index.html), and [Groovy](http://codemirror.net/mode/groovy/index.html) modes.
+*   Dragging text inside the editor now moves, rather than copies.
+*   Add a [`coordsFromIndex`](http://codemirror.net/doc/manual.html#coordsFromIndex) method.
+*   **API change**: `setValue` now no longer clears history. Use [`clearHistory`](http://codemirror.net/doc/manual.html#clearHistory) for that.
+*   **API change**: [`markText`](http://codemirror.net/doc/manual.html#markText) now returns an object with `clear` and `find` methods. Marked text is now more robust when edited.
+*   Fix editing code with tabs in Internet Explorer.
+
+## 2.15.0 (2011-09-26)
+
+Fix bug that snuck into 2.14: Clicking the character that currently has the cursor didn't re-focus the editor.
+
+## 2.14.0 (2011-09-26)
+
+*   Add [Clojure](http://codemirror.net/mode/clojure/index.html), [Pascal](http://codemirror.net/mode/pascal/index.html), [NTriples](http://codemirror.net/mode/ntriples/index.html), [Jinja2](http://codemirror.net/mode/jinja2/index.html), and [Markdown](http://codemirror.net/mode/markdown/index.html) modes.
+*   Add [Cobalt](http://codemirror.net/theme/cobalt.css) and [Eclipse](http://codemirror.net/theme/eclipse.css) themes.
+*   Add a [`fixedGutter`](http://codemirror.net/doc/manual.html#option_fixedGutter) option.
+*   Fix bug with `setValue` breaking cursor movement.
+*   Make gutter updates much more efficient.
+*   Allow dragging of text out of the editor (on modern browsers).
+
+## 2.13.0 (2011-08-23)
+
+*   Add [Ruby](http://codemirror.net/mode/ruby/index.html), [R](http://codemirror.net/mode/r/index.html), [CoffeeScript](http://codemirror.net/mode/coffeescript/index.html), and [Velocity](http://codemirror.net/mode/velocity/index.html) modes.
+*   Add [`getGutterElement`](http://codemirror.net/doc/manual.html#getGutterElement) to API.
+*   Several fixes to scrolling and positioning.
+*   Add [`smartHome`](http://codemirror.net/doc/manual.html#option_smartHome) option.
+*   Add an experimental [pure XML](http://codemirror.net/mode/xmlpure/index.html) mode.
+
+## 2.12.0 (2011-07-25)
+
+*   Add a [SPARQL](http://codemirror.net/mode/sparql/index.html) mode.
+*   Fix bug with cursor jumping around in an unfocused editor in IE.
+*   Allow key and mouse events to bubble out of the editor. Ignore widget clicks.
+*   Solve cursor flakiness after undo/redo.
+*   Fix block-reindent ignoring the last few lines.
+*   Fix parsing of multi-line attrs in XML mode.
+*   Use `innerHTML` for HTML-escaping.
+*   Some fixes to indentation in C-like mode.
+*   Shrink horiz scrollbars when long lines removed.
+*   Fix width feedback loop bug that caused the width of an inner DIV to shrink.
+
+## 2.11.0 (2011-07-04)
+
+*   Add a [Scheme mode](http://codemirror.net/mode/scheme/index.html).
+*   Add a `replace` method to search cursors, for cursor-preserving replacements.
+*   Make the [C-like mode](http://codemirror.net/mode/clike/index.html) mode more customizable.
+*   Update XML mode to spot mismatched tags.
+*   Add `getStateAfter` API and `compareState` mode API methods for finer-grained mode magic.
+*   Add a `getScrollerElement` API method to manipulate the scrolling DIV.
+*   Fix drag-and-drop for Firefox.
+*   Add a C# configuration for the [C-like mode](http://codemirror.net/mode/clike/index.html).
+*   Add [full-screen editing](http://codemirror.net/demo/fullscreen.html) and [mode-changing](http://codemirror.net/demo/changemode.html) demos.
+
+## 2.10.0 (2011-06-07)
+
+Add a [theme](http://codemirror.net/doc/manual.html#option_theme) system ([demo](http://codemirror.net/demo/theme.html)). Note that this is not backwards-compatible—you'll have to update your styles and modes!
+
+## 2.2.0 (2011-06-07)
+
+*   Add a [Lua mode](http://codemirror.net/mode/lua/index.html).
+*   Fix reverse-searching for a regexp.
+*   Empty lines can no longer break highlighting.
+*   Rework scrolling model (the outer wrapper no longer does the scrolling).
+*   Solve horizontal jittering on long lines.
+*   Add [runmode.js](http://codemirror.net/demo/runmode.html).
+*   Immediately re-highlight text when typing.
+*   Fix problem with 'sticking' horizontal scrollbar.
+
+## 2.1.0 (2011-05-26)
+
+*   Add a [Smalltalk mode](http://codemirror.net/mode/smalltalk/index.html).
+*   Add a [reStructuredText mode](http://codemirror.net/mode/rst/index.html).
+*   Add a [Python mode](http://codemirror.net/mode/python/index.html).
+*   Add a [PL/SQL mode](http://codemirror.net/mode/plsql/index.html).
+*   `coordsChar` now works
+*   Fix a problem where `onCursorActivity` interfered with `onChange`.
+*   Fix a number of scrolling and mouse-click-position glitches.
+*   Pass information about the changed lines to `onChange`.
+*   Support cmd-up/down on OS X.
+*   Add triple-click line selection.
+*   Don't handle shift when changing the selection through the API.
+*   Support `"nocursor"` mode for `readOnly` option.
+*   Add an `onHighlightComplete` option.
+*   Fix the context menu for Firefox.
+
+## 2.0.0 (2011-03-28)
+
+CodeMirror 2 is a complete rewrite that's faster, smaller, simpler to use, and less dependent on browser quirks. See [this](http://codemirror.net/doc/internals.html) and [this](http://groups.google.com/group/codemirror/browse_thread/thread/5a8e894024a9f580) for more information.
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/CONTRIBUTING.md b/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/CONTRIBUTING.md
new file mode 100644 (file)
index 0000000..1b0b104
--- /dev/null
@@ -0,0 +1,92 @@
+# How to contribute
+
+- [Getting help](#getting-help)
+- [Submitting bug reports](#submitting-bug-reports)
+- [Contributing code](#contributing-code)
+
+## Getting help
+
+Community discussion, questions, and informal bug reporting is done on the
+[discuss.CodeMirror forum](http://discuss.codemirror.net).
+
+## Submitting bug reports
+
+The preferred way to report bugs is to use the
+[GitHub issue tracker](http://github.com/codemirror/CodeMirror/issues). Before
+reporting a bug, read these pointers.
+
+**Note:** The issue tracker is for *bugs*, not requests for help. Questions
+should be asked on the
+[discuss.CodeMirror forum](http://discuss.codemirror.net) instead.
+
+### Reporting bugs effectively
+
+- CodeMirror is maintained by volunteers. They don't owe you anything, so be
+  polite. Reports with an indignant or belligerent tone tend to be moved to the
+  bottom of the pile.
+
+- Include information about **the browser in which the problem occurred**. Even
+  if you tested several browsers, and the problem occurred in all of them,
+  mention this fact in the bug report. Also include browser version numbers and
+  the operating system that you're on.
+
+- Mention which release of CodeMirror you're using. Preferably, try also with
+  the current development snapshot, to ensure the problem has not already been
+  fixed.
+
+- Mention very precisely what went wrong. "X is broken" is not a good bug
+  report. What did you expect to happen? What happened instead? Describe the
+  exact steps a maintainer has to take to make the problem occur. We can not
+  fix something that we can not observe.
+
+- If the problem can not be reproduced in any of the demos included in the
+  CodeMirror distribution, please provide an HTML document that demonstrates
+  the problem. The best way to do this is to go to
+  [jsbin.com](http://jsbin.com/ihunin/edit), enter it there, press save, and
+  include the resulting link in your bug report.
+
+## Contributing code
+
+Note that we are not accepting any new addons or modes into the main
+distribution. If you've written such a module, please distribute it as
+a separate NPM package.
+
+- Make sure you have a [GitHub Account](https://github.com/signup/free)
+- Fork [CodeMirror](https://github.com/codemirror/CodeMirror/)
+  ([how to fork a repo](https://help.github.com/articles/fork-a-repo))
+- Make your changes
+- If your changes are easy to test or likely to regress, add tests.
+  Tests for the core go into `test/test.js`, some modes have their own
+  test suite under `mode/XXX/test.js`. Feel free to add new test
+  suites to modes that don't have one yet (be sure to link the new
+  tests into `test/index.html`).
+- Follow the general code style of the rest of the project (see
+  below). Run `bin/lint` to verify that the linter is happy.
+- Make sure all tests pass. Visit `test/index.html` in your browser to
+  run them.
+- Submit a pull request
+([how to create a pull request](https://help.github.com/articles/fork-a-repo)).
+  Don't put more than one feature/fix in a single pull request.
+
+By contributing code to CodeMirror you
+
+ - agree to license the contributed code under CodeMirror's [MIT
+   license](http://codemirror.net/LICENSE).
+
+ - confirm that you have the right to contribute and license the code
+   in question. (Either you hold all rights on the code, or the rights
+   holder has explicitly granted the right to use it like this,
+   through a compatible open source license or through a direct
+   agreement with you.)
+
+### Coding standards
+
+- 2 spaces per indentation level, no tabs.
+
+- Note that the linter (`bin/lint`) which is run after each commit
+  complains about unused variables and functions. Prefix their names
+  with an underscore to muffle it.
+
+- CodeMirror does *not* follow JSHint or JSLint prescribed style.
+  Patches that try to 'fix' code to pass one of these linters will be
+  unceremoniously discarded.
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/LICENSE b/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/LICENSE
new file mode 100644 (file)
index 0000000..ff7db4b
--- /dev/null
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (C) 2017 by Marijn Haverbeke <marijnh@gmail.com> and others
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/README.md b/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/README.md
new file mode 100644 (file)
index 0000000..3328e3b
--- /dev/null
@@ -0,0 +1,34 @@
+# CodeMirror
+[![Build Status](https://travis-ci.org/codemirror/CodeMirror.svg)](https://travis-ci.org/codemirror/CodeMirror)
+[![NPM version](https://img.shields.io/npm/v/codemirror.svg)](https://www.npmjs.org/package/codemirror)
+[![Join the chat at https://gitter.im/codemirror/CodeMirror](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/codemirror/CodeMirror)  
+[Funding status: ![maintainer happiness](https://marijnhaverbeke.nl/fund/status_s.png?again)](https://marijnhaverbeke.nl/fund/)
+
+CodeMirror is a versatile text editor implemented in JavaScript for
+the browser. It is specialized for editing code, and comes with over
+100 language modes and various addons that implement more advanced
+editing functionality.
+
+A rich programming API and a CSS theming system are available for
+customizing CodeMirror to fit your application, and extending it with
+new functionality.
+
+You can find more information (and the
+[manual](http://codemirror.net/doc/manual.html)) on the [project
+page](http://codemirror.net). For questions and discussion, use the
+[discussion forum](https://discuss.codemirror.net/).
+
+See
+[CONTRIBUTING.md](https://github.com/codemirror/CodeMirror/blob/master/CONTRIBUTING.md)
+for contributing guidelines.
+
+The CodeMirror community aims to be welcoming to everybody. We use the
+[Contributor Covenant
+(1.1)](http://contributor-covenant.org/version/1/1/0/) as our code of
+conduct.
+
+### Quickstart
+
+To build the project, make sure you have Node.js installed (at least version 6)
+and then `npm install`. To run, just open `index.html` in your
+browser (you don't need to run a webserver). Run the tests with `npm test`.
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/comment/comment.js b/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/comment/comment.js
new file mode 100644 (file)
index 0000000..568e639
--- /dev/null
@@ -0,0 +1,213 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+
+  var noOptions = {};
+  var nonWS = /[^\s\u00a0]/;
+  var Pos = CodeMirror.Pos;
+
+  function firstNonWS(str) {
+    var found = str.search(nonWS);
+    return found == -1 ? 0 : found;
+  }
+
+  CodeMirror.commands.toggleComment = function(cm) {
+    cm.toggleComment();
+  };
+
+  CodeMirror.defineExtension("toggleComment", function(options) {
+    if (!options) options = noOptions;
+    var cm = this;
+    var minLine = Infinity, ranges = this.listSelections(), mode = null;
+    for (var i = ranges.length - 1; i >= 0; i--) {
+      var from = ranges[i].from(), to = ranges[i].to();
+      if (from.line >= minLine) continue;
+      if (to.line >= minLine) to = Pos(minLine, 0);
+      minLine = from.line;
+      if (mode == null) {
+        if (cm.uncomment(from, to, options)) mode = "un";
+        else { cm.lineComment(from, to, options); mode = "line"; }
+      } else if (mode == "un") {
+        cm.uncomment(from, to, options);
+      } else {
+        cm.lineComment(from, to, options);
+      }
+    }
+  });
+
+  // Rough heuristic to try and detect lines that are part of multi-line string
+  function probablyInsideString(cm, pos, line) {
+    return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"\`]/.test(line)
+  }
+
+  function getMode(cm, pos) {
+    var mode = cm.getMode()
+    return mode.useInnerComments === false || !mode.innerMode ? mode : cm.getModeAt(pos)
+  }
+
+  CodeMirror.defineExtension("lineComment", function(from, to, options) {
+    if (!options) options = noOptions;
+    var self = this, mode = getMode(self, from);
+    var firstLine = self.getLine(from.line);
+    if (firstLine == null || probablyInsideString(self, from, firstLine)) return;
+
+    var commentString = options.lineComment || mode.lineComment;
+    if (!commentString) {
+      if (options.blockCommentStart || mode.blockCommentStart) {
+        options.fullLines = true;
+        self.blockComment(from, to, options);
+      }
+      return;
+    }
+
+    var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
+    var pad = options.padding == null ? " " : options.padding;
+    var blankLines = options.commentBlankLines || from.line == to.line;
+
+    self.operation(function() {
+      if (options.indent) {
+        var baseString = null;
+        for (var i = from.line; i < end; ++i) {
+          var line = self.getLine(i);
+          var whitespace = line.slice(0, firstNonWS(line));
+          if (baseString == null || baseString.length > whitespace.length) {
+            baseString = whitespace;
+          }
+        }
+        for (var i = from.line; i < end; ++i) {
+          var line = self.getLine(i), cut = baseString.length;
+          if (!blankLines && !nonWS.test(line)) continue;
+          if (line.slice(0, cut) != baseString) cut = firstNonWS(line);
+          self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));
+        }
+      } else {
+        for (var i = from.line; i < end; ++i) {
+          if (blankLines || nonWS.test(self.getLine(i)))
+            self.replaceRange(commentString + pad, Pos(i, 0));
+        }
+      }
+    });
+  });
+
+  CodeMirror.defineExtension("blockComment", function(from, to, options) {
+    if (!options) options = noOptions;
+    var self = this, mode = getMode(self, from);
+    var startString = options.blockCommentStart || mode.blockCommentStart;
+    var endString = options.blockCommentEnd || mode.blockCommentEnd;
+    if (!startString || !endString) {
+      if ((options.lineComment || mode.lineComment) && options.fullLines != false)
+        self.lineComment(from, to, options);
+      return;
+    }
+    if (/\bcomment\b/.test(self.getTokenTypeAt(Pos(from.line, 0)))) return
+
+    var end = Math.min(to.line, self.lastLine());
+    if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;
+
+    var pad = options.padding == null ? " " : options.padding;
+    if (from.line > end) return;
+
+    self.operation(function() {
+      if (options.fullLines != false) {
+        var lastLineHasText = nonWS.test(self.getLine(end));
+        self.replaceRange(pad + endString, Pos(end));
+        self.replaceRange(startString + pad, Pos(from.line, 0));
+        var lead = options.blockCommentLead || mode.blockCommentLead;
+        if (lead != null) for (var i = from.line + 1; i <= end; ++i)
+          if (i != end || lastLineHasText)
+            self.replaceRange(lead + pad, Pos(i, 0));
+      } else {
+        self.replaceRange(endString, to);
+        self.replaceRange(startString, from);
+      }
+    });
+  });
+
+  CodeMirror.defineExtension("uncomment", function(from, to, options) {
+    if (!options) options = noOptions;
+    var self = this, mode = getMode(self, from);
+    var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end);
+
+    // Try finding line comments
+    var lineString = options.lineComment || mode.lineComment, lines = [];
+    var pad = options.padding == null ? " " : options.padding, didSomething;
+    lineComment: {
+      if (!lineString) break lineComment;
+      for (var i = start; i <= end; ++i) {
+        var line = self.getLine(i);
+        var found = line.indexOf(lineString);
+        if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
+        if (found == -1 && nonWS.test(line)) break lineComment;
+        if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
+        lines.push(line);
+      }
+      self.operation(function() {
+        for (var i = start; i <= end; ++i) {
+          var line = lines[i - start];
+          var pos = line.indexOf(lineString), endPos = pos + lineString.length;
+          if (pos < 0) continue;
+          if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
+          didSomething = true;
+          self.replaceRange("", Pos(i, pos), Pos(i, endPos));
+        }
+      });
+      if (didSomething) return true;
+    }
+
+    // Try block comments
+    var startString = options.blockCommentStart || mode.blockCommentStart;
+    var endString = options.blockCommentEnd || mode.blockCommentEnd;
+    if (!startString || !endString) return false;
+    var lead = options.blockCommentLead || mode.blockCommentLead;
+    var startLine = self.getLine(start), open = startLine.indexOf(startString)
+    if (open == -1) return false
+    var endLine = end == start ? startLine : self.getLine(end)
+    var close = endLine.indexOf(endString, end == start ? open + startString.length : 0);
+    if (close == -1 && start != end) {
+      endLine = self.getLine(--end);
+      close = endLine.indexOf(endString);
+    }
+    var insideStart = Pos(start, open + 1), insideEnd = Pos(end, close + 1)
+    if (close == -1 ||
+        !/comment/.test(self.getTokenTypeAt(insideStart)) ||
+        !/comment/.test(self.getTokenTypeAt(insideEnd)) ||
+        self.getRange(insideStart, insideEnd, "\n").indexOf(endString) > -1)
+      return false;
+
+    // Avoid killing block comments completely outside the selection.
+    // Positions of the last startString before the start of the selection, and the first endString after it.
+    var lastStart = startLine.lastIndexOf(startString, from.ch);
+    var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length);
+    if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false;
+    // Positions of the first endString after the end of the selection, and the last startString before it.
+    firstEnd = endLine.indexOf(endString, to.ch);
+    var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch);
+    lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart;
+    if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false;
+
+    self.operation(function() {
+      self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
+                        Pos(end, close + endString.length));
+      var openEnd = open + startString.length;
+      if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;
+      self.replaceRange("", Pos(start, open), Pos(start, openEnd));
+      if (lead) for (var i = start + 1; i <= end; ++i) {
+        var line = self.getLine(i), found = line.indexOf(lead);
+        if (found == -1 || nonWS.test(line.slice(0, found))) continue;
+        var foundEnd = found + lead.length;
+        if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;
+        self.replaceRange("", Pos(i, found), Pos(i, foundEnd));
+      }
+    });
+    return true;
+  });
+});
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/comment/continuecomment.js b/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/comment/continuecomment.js
new file mode 100644 (file)
index 0000000..b11d51e
--- /dev/null
@@ -0,0 +1,85 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  var modes = ["clike", "css", "javascript"];
+
+  for (var i = 0; i < modes.length; ++i)
+    CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "});
+
+  function continueComment(cm) {
+    if (cm.getOption("disableInput")) return CodeMirror.Pass;
+    var ranges = cm.listSelections(), mode, inserts = [];
+    for (var i = 0; i < ranges.length; i++) {
+      var pos = ranges[i].head, token = cm.getTokenAt(pos);
+      if (token.type != "comment") return CodeMirror.Pass;
+      var modeHere = CodeMirror.innerMode(cm.getMode(), token.state).mode;
+      if (!mode) mode = modeHere;
+      else if (mode != modeHere) return CodeMirror.Pass;
+
+      var insert = null;
+      if (mode.blockCommentStart && mode.blockCommentContinue) {
+        var end = token.string.indexOf(mode.blockCommentEnd);
+        var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found;
+        if (end != -1 && end == token.string.length - mode.blockCommentEnd.length && pos.ch >= end) {
+          // Comment ended, don't continue it
+        } else if (token.string.indexOf(mode.blockCommentStart) == 0) {
+          insert = full.slice(0, token.start);
+          if (!/^\s*$/.test(insert)) {
+            insert = "";
+            for (var j = 0; j < token.start; ++j) insert += " ";
+          }
+        } else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 &&
+                   found + mode.blockCommentContinue.length > token.start &&
+                   /^\s*$/.test(full.slice(0, found))) {
+          insert = full.slice(0, found);
+        }
+        if (insert != null) insert += mode.blockCommentContinue;
+      }
+      if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) {
+        var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment);
+        if (found > -1) {
+          insert = line.slice(0, found);
+          if (/\S/.test(insert)) insert = null;
+          else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0];
+        }
+      }
+      if (insert == null) return CodeMirror.Pass;
+      inserts[i] = "\n" + insert;
+    }
+
+    cm.operation(function() {
+      for (var i = ranges.length - 1; i >= 0; i--)
+        cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert");
+    });
+  }
+
+  function continueLineCommentEnabled(cm) {
+    var opt = cm.getOption("continueComments");
+    if (opt && typeof opt == "object")
+      return opt.continueLineComment !== false;
+    return true;
+  }
+
+  CodeMirror.defineOption("continueComments", null, function(cm, val, prev) {
+    if (prev && prev != CodeMirror.Init)
+      cm.removeKeyMap("continueComment");
+    if (val) {
+      var key = "Enter";
+      if (typeof val == "string")
+        key = val;
+      else if (typeof val == "object" && val.key)
+        key = val.key;
+      var map = {name: "continueComment"};
+      map[key] = continueComment;
+      cm.addKeyMap(map);
+    }
+  });
+});
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/dialog/dialog.css b/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/dialog/dialog.css
new file mode 100644 (file)
index 0000000..677c078
--- /dev/null
@@ -0,0 +1,32 @@
+.CodeMirror-dialog {
+  position: absolute;
+  left: 0; right: 0;
+  background: inherit;
+  z-index: 15;
+  padding: .1em .8em;
+  overflow: hidden;
+  color: inherit;
+}
+
+.CodeMirror-dialog-top {
+  border-bottom: 1px solid #eee;
+  top: 0;
+}
+
+.CodeMirror-dialog-bottom {
+  border-top: 1px solid #eee;
+  bottom: 0;
+}
+
+.CodeMirror-dialog input {
+  border: none;
+  outline: none;
+  background: transparent;
+  width: 20em;
+  color: inherit;
+  font-family: monospace;
+}
+
+.CodeMirror-dialog button {
+  font-size: 70%;
+}
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/dialog/dialog.js b/typo3/sysext/t3editor/Resources/Public/JavaScript/Contrib/cm/addon/dialog/dialog.js
new file mode 100644 (file)
index 0000000..f10bb5b
--- /dev/null
@@ -0,0 +1,157 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+// Open simple dialogs on top of an editor. Relies on dialog.css.
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  function dialogDiv(cm, template, bottom) {
+    var wrap = cm.getWrapperElement();
+    var dialog;
+    dialog = wrap.appendChild(document.createElement("div"));
+    if (bottom)
+      dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
+    else
+      dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
+
+    if (typeof template == "string") {
+      dialog.innerHTML = template;
+    } else { // Assuming it's a detached DOM element.
+      dialog.appendChild(template);
+    }
+    return dialog;
+  }
+
+  function closeNotification(cm, newVal) {
+    if (cm.state.currentNotificationClose)
+      cm.state.currentNotificationClose();
+    cm.state.currentNotificationClose = newVal;
+  }
+
+  CodeMirror.defineExtension("openDialog", function(template, callback, options) {
+    if (!options) options = {};
+
+    closeNotification(this, null);
+
+    var dialog = dialogDiv(this, template, options.bottom);
+    var closed = false, me = this;
+    function close(newVal) {
+      if (typeof newVal == 'string') {
+        inp.value = newVal;
+      } else {
+        if (closed) return;
+        closed = true;
+        dialog.parentNode.removeChild(dialog);
+        me.focus();
+
+        if (options.onClose) options.onClose(dialog);
+      }
+    }
+
+    var inp = dialog.getElementsByTagName("input")[0], button;
+    if (inp) {
+      inp.focus();
+
+      if (options.value) {
+        inp.value = options.value;
+