Add `SourceCodeFormField`
authorMatthias Schmidt <gravatronics@live.com>
Mon, 14 Jun 2021 05:42:57 +0000 (07:42 +0200)
committerMatthias Schmidt <gravatronics@live.com>
Mon, 14 Jun 2021 05:42:57 +0000 (07:42 +0200)
com.woltlab.wcf/templates/__sourceCodeFormField.tpl [new file with mode: 0644]
syncTemplates.json
wcfsetup/install/files/acp/templates/__sourceCodeFormField.tpl [new file with mode: 0644]
wcfsetup/install/files/lib/system/form/builder/field/SourceCodeFormField.class.php [new file with mode: 0644]

diff --git a/com.woltlab.wcf/templates/__sourceCodeFormField.tpl b/com.woltlab.wcf/templates/__sourceCodeFormField.tpl
new file mode 100644 (file)
index 0000000..6fbf197
--- /dev/null
@@ -0,0 +1,18 @@
+<textarea id="{@$field->getPrefixedId()}" {*
+    *}name="{@$field->getPrefixedId()}" {*
+    *}{if !$field->getFieldClasses()|empty} class="{implode from=$field->getFieldClasses() item='class' glue=' '}{$class}{/implode}"{/if}{*
+    *}{if $field->isRequired()} required{/if}{*
+    *}{if $field->isAutofocused()} autofocus{/if}{*
+    *}{if $field->isImmutable()} disabled{/if}{*
+    *}{if $field->getMinimumLength() !== null} minlength="{$field->getMinimumLength()}"{/if}{*
+    *}{if $field->getMaximumLength() !== null} maxlength="{$field->getMaximumLength()}"{/if}{*
+    *}{foreach from=$field->getFieldAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach}{*
+*}>{$field->getValue()}</textarea>
+
+{include file='codemirror' codemirrorMode=$field->getLanguage() codemirrorSelector='#'|concat:$field->getPrefixedId()}
+
+<script data-relocate="true">
+    (() => {
+        document.getElementById('{@$field->getPrefixedId()}').parentNode.dir = 'ltr';
+    })();
+</script>
index 60709bd8678a05920c40a425bc3ad66f9a08c48f..fcd4ed90c50256b96e5323aeda0f87f8c94d1b03 100644 (file)
@@ -41,6 +41,7 @@
     "__rowFormFieldContainer",
     "__singleMediaSelectionFormField",
     "__singleSelectionFormField",
+    "__sourceCodeFormField",
     "__suffixFormFieldContainer",
     "__tabFormContainer",
     "__tabMenuFormContainer",
diff --git a/wcfsetup/install/files/acp/templates/__sourceCodeFormField.tpl b/wcfsetup/install/files/acp/templates/__sourceCodeFormField.tpl
new file mode 100644 (file)
index 0000000..6fbf197
--- /dev/null
@@ -0,0 +1,18 @@
+<textarea id="{@$field->getPrefixedId()}" {*
+    *}name="{@$field->getPrefixedId()}" {*
+    *}{if !$field->getFieldClasses()|empty} class="{implode from=$field->getFieldClasses() item='class' glue=' '}{$class}{/implode}"{/if}{*
+    *}{if $field->isRequired()} required{/if}{*
+    *}{if $field->isAutofocused()} autofocus{/if}{*
+    *}{if $field->isImmutable()} disabled{/if}{*
+    *}{if $field->getMinimumLength() !== null} minlength="{$field->getMinimumLength()}"{/if}{*
+    *}{if $field->getMaximumLength() !== null} maxlength="{$field->getMaximumLength()}"{/if}{*
+    *}{foreach from=$field->getFieldAttributes() key='attributeName' item='attributeValue'} {$attributeName}="{$attributeValue}"{/foreach}{*
+*}>{$field->getValue()}</textarea>
+
+{include file='codemirror' codemirrorMode=$field->getLanguage() codemirrorSelector='#'|concat:$field->getPrefixedId()}
+
+<script data-relocate="true">
+    (() => {
+        document.getElementById('{@$field->getPrefixedId()}').parentNode.dir = 'ltr';
+    })();
+</script>
diff --git a/wcfsetup/install/files/lib/system/form/builder/field/SourceCodeFormField.class.php b/wcfsetup/install/files/lib/system/form/builder/field/SourceCodeFormField.class.php
new file mode 100644 (file)
index 0000000..9d1fde2
--- /dev/null
@@ -0,0 +1,223 @@
+<?php
+
+namespace wcf\system\form\builder\field;
+
+use wcf\system\form\builder\field\validation\FormFieldValidationError;
+
+/**
+ * Implementation of a form field to enter source code.
+ *
+ * @author  Matthias Schmidt
+ * @copyright   2001-2021 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Form\Builder\Field
+ * @since   5.5
+ */
+class SourceCodeFormField extends AbstractFormField implements
+    IAttributeFormField,
+    IAutoFocusFormField,
+    ICssClassFormField,
+    IImmutableFormField,
+    IMaximumLengthFormField,
+    IMinimumLengthFormField,
+    INullableFormField
+{
+    use TAttributeFormField;
+    use TAutoFocusFormField;
+    use TCssClassFormField;
+    use TImmutableFormField;
+    use TMaximumLengthFormField;
+    use TMinimumLengthFormField;
+    use TNullableFormField;
+
+    /**
+     * @var string|null
+     */
+    protected $language;
+
+    /**
+     * @inheritDoc
+     */
+    protected $templateName = '__sourceCodeFormField';
+
+    public const LANGUAGES = [
+        // Languages supported by CodeMirror itself.
+        'apl',
+        'asciiarmor',
+        'asn.1',
+        'asterisk',
+        'brainfuck',
+        'clike',
+        'clojure',
+        'cmake',
+        'cobol',
+        'coffeescript',
+        'commonlisp',
+        'crystal',
+        'css',
+        'cypher',
+        'd',
+        'dart',
+        'diff',
+        'django',
+        'dockerfile',
+        'dtd',
+        'dylan',
+        'ebnf',
+        'ecl',
+        'eiffel',
+        'elm',
+        'erlang',
+        'factor',
+        'fcl',
+        'forth',
+        'fortran',
+        'gas',
+        'gfm',
+        'gherkin',
+        'go',
+        'groovy',
+        'haml',
+        'handlebars',
+        'haskell',
+        'haskell-literate',
+        'haxe',
+        'htmlembedded',
+        'htmlmixed',
+        'http',
+        'idl',
+        'javascript',
+        'jinja2',
+        'jsx',
+        'julia',
+        'livescript',
+        'lua',
+        'markdown',
+        'mathematica',
+        'mbox',
+        'mirc',
+        'mllike',
+        'modelica',
+        'mscgen',
+        'mumps',
+        'nginx',
+        'nsis',
+        'ntriples',
+        'octave',
+        'oz',
+        'pascal',
+        'pegjs',
+        'perl',
+        'php',
+        'pig',
+        'powershell',
+        'properties',
+        'protobuf',
+        'pug',
+        'puppet',
+        'python',
+        'q',
+        'r',
+        'rpm',
+        'rst',
+        'ruby',
+        'rust',
+        'sas',
+        'sass',
+        'scheme',
+        'shell',
+        'sieve',
+        'slim',
+        'smalltalk',
+        'smarty',
+        'solr',
+        'soy',
+        'sparql',
+        'spreadsheet',
+        'sql',
+        'stex',
+        'stylus',
+        'swift',
+        'tcl',
+        'textile',
+        'tiddlywiki',
+        'tiki',
+        'toml',
+        'tornado',
+        'troff',
+        'ttcn',
+        'ttcn-cfg',
+        'turtle',
+        'twig',
+        'vb',
+        'vbscript',
+        'velocity',
+        'verilog',
+        'vhdl',
+        'vue',
+        'wast',
+        'webidl',
+        'xml',
+        'xquery',
+        'yacas',
+        'yaml',
+        'yaml-frontmatter',
+        'z80',
+
+        // Additional language added/supported by us.
+        'smartymixed',
+    ];
+
+    /**
+     * Returns the source code language used or `null` if no language is specified.
+     *
+     * By default, `null` is returned.
+     */
+    public function getLanguage(): ?string
+    {
+        return $this->language;
+    }
+
+    /**
+     * Sets the source code language used or unset a previously set language if `null` is given.
+     *
+     * @throws  \InvalidArgumentException   if given language is unsupported
+     */
+    public function language(?string $language): self
+    {
+        if (!\in_array($language, self::LANGUAGES)) {
+            throw new \InvalidArgumentException("Unsupported language '{$language}' given.");
+        }
+
+        $this->language = $language;
+
+        return $this;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function readValue()
+    {
+        if ($this->getDocument()->hasRequestData($this->getPrefixedId())) {
+            $this->value = $this->getDocument()->getRequestData($this->getPrefixedId());
+        }
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function validate()
+    {
+        if ($this->value === null || $this->value === '') {
+            if ($this->isRequired()) {
+                $this->addValidationError(new FormFieldValidationError('empty'));
+            }
+        } else {
+            $this->validateMinimumLength($this->value);
+            $this->validateMaximumLength($this->value);
+        }
+
+        parent::validate();
+    }
+}