Przeglądaj źródła

Merge pull request #14 from forkbb/SCEditor

Add SCEditor
Visman 2 lat temu
rodzic
commit
e75897f0a1
49 zmienionych plików z 10807 dodań i 100 usunięć
  1. 3 1
      app/Models/Page.php
  2. 27 1
      app/Models/Pages/Admin/Update.php
  3. 82 0
      app/Models/Pages/PostFormTrait.php
  4. 1 1
      app/bootstrap.php
  5. 96 31
      app/config/defaultBBCode.php
  6. 22 0
      public/js/sc/LICENSE.md
  7. 2649 0
      public/js/sc/formats/bbcode.js
  8. 112 0
      public/js/sc/icons/monocons.js
  9. 68 0
      public/js/sc/languages/ar.js
  10. 68 0
      public/js/sc/languages/ca.js
  11. 68 0
      public/js/sc/languages/cn.js
  12. 71 0
      public/js/sc/languages/cs.js
  13. 61 0
      public/js/sc/languages/de.js
  14. 68 0
      public/js/sc/languages/el.js
  15. 7 0
      public/js/sc/languages/en-US.js
  16. 12 0
      public/js/sc/languages/en.js
  17. 68 0
      public/js/sc/languages/es.js
  18. 57 0
      public/js/sc/languages/et.js
  19. 69 0
      public/js/sc/languages/fa.js
  20. 70 0
      public/js/sc/languages/fi.js
  21. 70 0
      public/js/sc/languages/fr.js
  22. 68 0
      public/js/sc/languages/gl.js
  23. 69 0
      public/js/sc/languages/hu.js
  24. 68 0
      public/js/sc/languages/id.js
  25. 72 0
      public/js/sc/languages/it.js
  26. 71 0
      public/js/sc/languages/ja.js
  27. 68 0
      public/js/sc/languages/lt.js
  28. 70 0
      public/js/sc/languages/nb.js
  29. 72 0
      public/js/sc/languages/nl.js
  30. 68 0
      public/js/sc/languages/pl.js
  31. 67 0
      public/js/sc/languages/pt-BR.js
  32. 69 0
      public/js/sc/languages/pt.js
  33. 60 0
      public/js/sc/languages/ru.js
  34. 70 0
      public/js/sc/languages/sk.js
  35. 58 0
      public/js/sc/languages/sv.js
  36. 80 0
      public/js/sc/languages/template.js
  37. 66 0
      public/js/sc/languages/tr.js
  38. 68 0
      public/js/sc/languages/tw.js
  39. 57 0
      public/js/sc/languages/uk.js
  40. 68 0
      public/js/sc/languages/vi.js
  41. 157 0
      public/js/sc/plugins/alternative-lists.js
  42. 4385 0
      public/js/sc/sceditor.js
  43. 98 0
      public/js/scloader.js
  44. 187 0
      public/style/ForkBB/sccontent.css
  45. 240 66
      public/style/ForkBB/style.css
  46. 22 0
      public/style/sc/LICENSE.md
  47. 85 0
      public/style/sc/themes/content/default.css
  48. 595 0
      public/style/sc/themes/default.css
  49. BIN
      public/style/sc/themes/famfamfam.png

+ 3 - 1
app/Models/Page.php

@@ -516,7 +516,7 @@ abstract class Page extends Model
      * Возвращает url для $path заданного в каталоге public
      * Ведущий слеш обязателен O_o
      */
-    public function publicLink(string $path): string
+    public function publicLink(string $path, bool $returnEmpty = false): string
     {
         $fullPath = $this->c->DIR_PUBLIC . $path;
 
@@ -526,6 +526,8 @@ abstract class Page extends Model
             if (\preg_match('%^(.+)\.([^.\\/]++)$%D', $path, $matches)) {
                 return $this->c->PUBLIC_URL . "{$matches[1]}.v.{$time}.{$matches[2]}";
             }
+        } elseif ($returnEmpty) {
+            return '';
         }
 
         return $this->c->PUBLIC_URL . $path;

+ 27 - 1
app/Models/Pages/Admin/Update.php

@@ -25,7 +25,7 @@ class Update extends Admin
 {
     const PHP_MIN                    = '7.3.0';
     const REV_MIN_FOR_UPDATE         = 42;
-    const LATEST_REV_WITH_DB_CHANGES = 43;
+    const LATEST_REV_WITH_DB_CHANGES = 51;
     const LOCK_NAME                  = 'lock_update';
     const LOCk_TTL                   = 1800;
     const JSON_OPTIONS               = \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE | \JSON_THROW_ON_ERROR;
@@ -748,4 +748,30 @@ class Update extends Admin
 
         return null;
     }
+
+    /**
+     * rev.50 to rev.51
+     */
+    protected function stageNumber50(array $args): ?int
+    {
+        $queryI  = 'INSERT INTO ::bbcode (bb_tag, bb_edit, bb_delete, bb_structure)
+            VALUES(?s:tag, 1, 0, ?s:structure)';
+        $queryU  = 'UPDATE ::bbcode
+            SET bb_edit=1, bb_delete=0, bb_structure=?s:structure
+            WHERE bb_tag=?s:tag';
+        $bbcodes = include $this->c->DIR_CONFIG . '/defaultBBCode.php';
+
+        foreach ($bbcodes as $bbcode) {
+            $vars = [
+                ':tag'       => $bbcode['tag'],
+                ':structure' => \json_encode($bbcode, self::JSON_OPTIONS),
+            ];
+            $exist = $this->c->DB->query('SELECT 1 FROM ::bbcode WHERE bb_tag=?s:tag', $vars)->fetchColumn();
+            $query = empty($exist) ? $queryI : $queryU;
+
+            $this->c->DB->exec($query, $vars);
+        }
+
+        return null;
+    }
 }

+ 82 - 0
app/Models/Pages/PostFormTrait.php

@@ -256,6 +256,88 @@ trait PostFormTrait
             ]);
         }
 
+        if (1 === $this->c->config->b_message_bbcode) {
+            $form = $this->setSCEditor($form, 'message');
+        }
+
+        return $form;
+    }
+
+    protected function setSCEditor(array $form, string $field)
+    {
+        foreach ($form['sets'] as &$section) {
+            if (empty($section['fields'])) {
+                continue;
+            }
+            foreach ($section['fields'] as $key => &$cur) {
+                if (
+                    $key === $field
+                    && isset($cur['type'])
+                    && 'textarea' === $cur['type']
+                ) {
+                    $smilies = $hidden = [];
+                    $smiliesEnabled    = '0';
+
+                    if (1 === $this->c->config->b_smilies) {
+                        $smiliesEnabled = '1';
+
+                        foreach ($this->c->smilies->list as $sm) {
+                            if (isset($smilies[$sm['sm_image']])) {
+                                $hidden[$sm['sm_code']] = $sm['sm_image'];
+                            } else {
+                                $smilies[$sm['sm_image']] = $sm['sm_code'];
+                            }
+                        }
+                    }
+
+                    $scConfig = \json_encode([
+                        'style'         => $this->publicLink("/style/{$this->user->style}/sccontent.css", true)
+                                            ?: $this->publicLink('/style/sc/themes/content/default.css'),
+                        'locale'        => __('lang_identifier'),
+                        'emoticonsRoot' => $this->c->PUBLIC_URL . '/img/sm/',
+                        'emoticons'     => [
+                            'dropdown' => \array_flip($smilies),
+                            'hidden'   => $hidden,
+                        ],
+                        'plugins' => 'alternative-lists',
+                    ]);
+                    $cur['data'] = [
+                        'SCEditorConfig' => $scConfig,
+                        'smiliesEnabled' => $smiliesEnabled,
+                        'linkEnabled'    => $this->c->user->g_post_links,
+                    ];
+
+                    $this->pageHeader('sceditor', 'script', 9600, [
+                        'src' => $this->publicLink('/js/sc/sceditor.js'),
+                    ]);
+                    $this->pageHeader('scmonocons', 'script', 9550, [
+                        'src' => $this->publicLink('/js/sc/icons/monocons.js'),
+                    ]);
+                    $this->pageHeader('scbbcode', 'script', 9550, [
+                        'src' => $this->publicLink('/js/sc/formats/bbcode.js'),
+                    ]);
+                    $this->pageHeader('scalternative-lists', 'script', 9550, [
+                        'src' => $this->publicLink('/js/sc/plugins/alternative-lists.js'),
+                    ]);
+                    $this->pageHeader('sclanguage', 'script', 9550, [
+                        'src' => $this->publicLink('/js/sc/languages/' . __('lang_identifier') . '.js'),
+                    ]);
+                    $this->pageHeader('scloader', 'script', 9500, [
+                        'src' => $this->publicLink('/js/scloader.js'),
+                    ]);
+                    $this->pageHeader('scdefaultstyle', 'link', 9500, [
+                        'rel'  => 'stylesheet',
+                        'type' => 'text/css',
+                        'href' => $this->publicLink("/style/sc/themes/default.css"),
+                    ]);
+
+                    unset($cur);
+
+                    break 2;
+                }
+            }
+        }
+
         return $form;
     }
 }

+ 1 - 1
app/bootstrap.php

@@ -58,7 +58,7 @@ if (
     $c->BASE_URL = \str_replace('https://', 'http://', $c->BASE_URL);
 }
 
-$c->FORK_REVISION = 50;
+$c->FORK_REVISION = 51;
 $c->START         = $forkStart;
 $c->PUBLIC_URL    = $c->BASE_URL . $forkPublicPrefix;
 

+ 96 - 31
app/config/defaultBBCode.php

@@ -13,18 +13,10 @@ return [
         'tag' => 'ROOT',
         'type' => 'block',
         'handler' => <<<'HANDLER'
-// Replace any breaks next to paragraphs so our replace below catches them
-$body = \preg_replace('%(</?p>)(?:\s*?<br>){1,2}%', '$1', '<p>' . $body . '</p>');
-$body = \preg_replace('%(?:<br>\s*?){1,2}(</?p>)%', '$1', $body);
-
-// Remove any empty paragraph tags (inserted via quotes/lists/code/etc) which should be stripped
+$body = '<p>' . $body . '</p>';
+$body = \str_replace('<p><br>', '<p>', $body);
 $body = \str_replace('<p></p>', '', $body);
-
-$body = \preg_replace('%<br>\s*?<br>%', '</p><p>', $body);
-
-$body = \str_replace('<p><br>', '<br><p>', $body);
-$body = \str_replace('<br></p>', '</p><br>', $body);
-$body = \str_replace('<p></p>', '<br><br>', $body);
+$body = \preg_replace('%<br>(?:\s*?<br>){3,}%', '<br><br><br>', $body);
 
 return $body;
 HANDLER,
@@ -82,6 +74,18 @@ HANDLER,
         'tag' => 'ins',
         'handler' => <<<'HANDLER'
 return "<ins>{$body}</ins>";
+HANDLER,
+    ],
+    [
+        'tag' => 'sub',
+        'handler' => <<<'HANDLER'
+return "<sub>{$body}</sub>";
+HANDLER,
+    ],
+    [
+        'tag' => 'sup',
+        'handler' => <<<'HANDLER'
+return "<sup>{$body}</sup>";
 HANDLER,
     ],
     [
@@ -108,7 +112,36 @@ HANDLER,
             ],
         ],
         'handler' => <<<'HANDLER'
-return "<span style=\"color:{$attrs['Def']};\">{$body}</span>";
+$color = $attrs['Def'];
+
+if ('#' === $color[0]) {
+    $color = \strtoupper($color);
+} else {
+    $repl = [
+        'black'   => '#000000',
+        'gray'    => '#808080',
+        'silver'  => '#C0C0C0',
+        'white'   => '#FFFFFF',
+        'fuchsia' => '#FF00FF',
+        'purple'  => '#800080',
+        'red'     => '#FF0000',
+        'maroon'  => '#800000',
+        'yellow'  => '#FFFF00',
+        'olive'   => '#808000',
+        'lime'    => '#00FF00',
+        'green'   => '#008000',
+        'aqua'    => '#00FFFF',
+        'teal'    => '#008080',
+        'blue'    => '#0000FF',
+        'navy'    => '#000080',
+    ];
+
+    if (isset($repl[$color])) {
+        $color = $repl[$color];
+    }
+}
+
+return "<span class=\"f-bb-color\" data-bb=\"{$color}\">{$body}</span>";
 HANDLER,
     ],
     [
@@ -120,7 +153,36 @@ HANDLER,
             ],
         ],
         'handler' => <<<'HANDLER'
-return "<span style=\"color:{$attrs['Def']};\">{$body}</span>";
+$color = $attrs['Def'];
+
+if ('#' === $color[0]) {
+    $color = \strtoupper($color);
+} else {
+    $repl = [
+        'black'   => '#000000',
+        'gray'    => '#808080',
+        'silver'  => '#C0C0C0',
+        'white'   => '#FFFFFF',
+        'fuchsia' => '#FF00FF',
+        'purple'  => '#800080',
+        'red'     => '#FF0000',
+        'maroon'  => '#800000',
+        'yellow'  => '#FFFF00',
+        'olive'   => '#808000',
+        'lime'    => '#00FF00',
+        'green'   => '#008000',
+        'aqua'    => '#00FFFF',
+        'teal'    => '#008080',
+        'blue'    => '#0000FF',
+        'navy'    => '#000080',
+    ];
+
+    if (isset($repl[$color])) {
+        $color = $repl[$color];
+    }
+}
+
+return "<span class=\"f-bb-color\" data-bb=\"{$color}\">{$body}</span>";
 HANDLER,
     ],
     [
@@ -140,36 +202,39 @@ HANDLER,
         'self_nesting' => 5,
         'attrs' => [
             'Def' => [
-                'format' => '%^[1-9]\d*(?:em|ex|pt|px|\%)?$%',
+                'format' => '%^[1-7]$%',
             ],
         ],
         'handler' => <<<'HANDLER'
-if (\is_numeric($attrs['Def'])) {
-    $attrs['Def'] .= 'px';
-}
-
-return "<span style=\"font-size:{$attrs['Def']};\">{$body}</span>";
+return "<span class=\"f-bb-size{$attrs['Def']}\">{$body}</span>";
+HANDLER,
+    ],
+    [
+        'tag' => 'left',
+        'type' => 'block',
+        'handler' => <<<'HANDLER'
+return "</p><p class=\"f-bb-left\">{$body}</p><p>";
 HANDLER,
     ],
     [
         'tag' => 'right',
         'type' => 'block',
         'handler' => <<<'HANDLER'
-return "</p><p class=\"text-align-right\">{$body}</p><p>";
+return "</p><p class=\"f-bb-right\">{$body}</p><p>";
 HANDLER,
     ],
     [
         'tag' => 'center',
         'type' => 'block',
         'handler' => <<<'HANDLER'
-return "</p><p class=\"text-align-center\">{$body}</p><p>";
+return "</p><p class=\"f-bb-center\">{$body}</p><p>";
 HANDLER,
     ],
     [
         'tag' => 'justify',
         'type' => 'block',
         'handler' => <<<'HANDLER'
-return "</p><p class=\"text-align-justify\">{$body}</p><p>";
+return "</p><p class=\"f-bb-justify\">{$body}</p><p>";
 HANDLER,
     ],
     [
@@ -187,7 +252,7 @@ HANDLER,
             ],
         ],
         'handler' => <<<'HANDLER'
-return "<span style=\"font-family:{$attrs['Def']};\">{$body}</span>";
+return "<span class=\"f-bb-font\" data-bb=\"{$attrs['Def']}\">{$body}</span>";
 HANDLER,
     ],
     [
@@ -402,7 +467,7 @@ foreach ($attrs as $key => $val) {
     $attr .= " {$key}=\"{$val}\"";
 }
 
-return "</p><table{$attr}>{$body}</table><p>";
+return "</p><table class=\"f-bb-table\"{$attr}>{$body}</table><p>";
 HANDLER,
     ],
     [
@@ -420,7 +485,7 @@ foreach ($attrs as $key => $val) {
     $attr .= " {$key}=\"{$val}\"";
 }
 
-return "<caption{$attr}><p>{$body}</p></caption>";
+return "<caption class=\"f-bb-caption\"{$attr}><p>{$body}</p></caption>";
 HANDLER,
     ],
     [
@@ -439,7 +504,7 @@ foreach ($attrs as $key => $val) {
     $attr .= " {$key}=\"{$val}\"";
 }
 
-return "<thead{$attr}>{$body}</thead>";
+return "<thead class=\"f-bb-thead\"{$attr}>{$body}</thead>";
 HANDLER,
     ],
     [
@@ -458,7 +523,7 @@ foreach ($attrs as $key => $val) {
     $attr .= " {$key}=\"{$val}\"";
 }
 
-return "<tbody{$attr}>{$body}</tbody>";
+return "<tbody class=\"f-bb-tbody\"{$attr}>{$body}</tbody>";
 HANDLER,
     ],
     [
@@ -477,7 +542,7 @@ foreach ($attrs as $key => $val) {
     $attr .= " {$key}=\"{$val}\"";
 }
 
-return "<tfoot{$attr}>{$body}</tfoot>";
+return "<tfoot class=\"f-bb-tfoot\"{$attr}>{$body}</tfoot>";
 HANDLER,
     ],
     [
@@ -496,7 +561,7 @@ foreach ($attrs as $key => $val) {
     $attr .= " {$key}=\"{$val}\"";
 }
 
-return "<tr{$attr}>{$body}</tr>";
+return "<tr class=\"f-bb-tr\"{$attr}>{$body}</tr>";
 HANDLER,
     ],
     [
@@ -516,7 +581,7 @@ foreach ($attrs as $key => $val) {
     $attr .= " {$key}=\"{$val}\"";
 }
 
-return "<th{$attr}><p>{$body}</p></th>";
+return "<th class=\"f-bb-th\"{$attr}><p>{$body}</p></th>";
 HANDLER,
     ],
     [
@@ -536,7 +601,7 @@ foreach ($attrs as $key => $val) {
     $attr .= " {$key}=\"{$val}\"";
 }
 
-return "<td{$attr}><p>{$body}</p></td>";
+return "<td class=\"f-bb-td\"{$attr}><p>{$body}</p></td>";
 HANDLER,
     ],
     [

+ 22 - 0
public/js/sc/LICENSE.md

@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (C) 2011-2016 by Sam Clarke and contributors
+http://www.sceditor.com/
+
+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.

+ 2649 - 0
public/js/sc/formats/bbcode.js

@@ -0,0 +1,2649 @@
+/**
+ * SCEditor BBCode Plugin
+ * http://www.sceditor.com/
+ *
+ * Copyright (C) 2011-2017, Sam Clarke (samclarke.com)
+ *
+ * SCEditor is licensed under the MIT license:
+ *	http://www.opensource.org/licenses/mit-license.php
+ *
+ * @fileoverview SCEditor BBCode Format
+ * @author Sam Clarke
+ */
+(function (sceditor) {
+	/*eslint max-depth: off*/
+	'use strict';
+
+	var escapeEntities  = sceditor.escapeEntities;
+	var escapeUriScheme = sceditor.escapeUriScheme;
+	var dom             = sceditor.dom;
+	var utils           = sceditor.utils;
+
+	var css    = dom.css;
+	var attr   = dom.attr;
+	var is     = dom.is;
+	var extend = utils.extend;
+	var each   = utils.each;
+
+	var EMOTICON_DATA_ATTR = 'data-sceditor-emoticon';
+
+	var getEditorCommand = sceditor.command.get;
+
+	var QuoteType = {
+		/** @lends BBCodeParser.QuoteType */
+		/**
+		 * Always quote the attribute value
+		 * @type {Number}
+		 */
+		always: 1,
+
+		/**
+		 * Never quote the attributes value
+		 * @type {Number}
+		 */
+		never: 2,
+
+		/**
+		 * Only quote the attributes value when it contains spaces to equals
+		 * @type {Number}
+		 */
+		auto: 3
+	};
+
+	var defaultCommandsOverrides = {
+		bold: {
+			txtExec: ['[b]', '[/b]']
+		},
+		italic: {
+			txtExec: ['[i]', '[/i]']
+		},
+		underline: {
+			txtExec: ['[u]', '[/u]']
+		},
+		strike: {
+			txtExec: ['[s]', '[/s]']
+		},
+		subscript: {
+			txtExec: ['[sub]', '[/sub]']
+		},
+		superscript: {
+			txtExec: ['[sup]', '[/sup]']
+		},
+		left: {
+			txtExec: ['[left]', '[/left]']
+		},
+		center: {
+			txtExec: ['[center]', '[/center]']
+		},
+		right: {
+			txtExec: ['[right]', '[/right]']
+		},
+		justify: {
+			txtExec: ['[justify]', '[/justify]']
+		},
+		font: {
+			txtExec: function (caller) {
+				var editor = this;
+
+				getEditorCommand('font')._dropDown(
+					editor,
+					caller,
+					function (fontName) {
+						editor.insertText(
+							'[font=' + fontName + ']',
+							'[/font]'
+						);
+					}
+				);
+			}
+		},
+		size: {
+			txtExec: function (caller) {
+				var editor = this;
+
+				getEditorCommand('size')._dropDown(
+					editor,
+					caller,
+					function (fontSize) {
+						editor.insertText(
+							'[size=' + fontSize + ']',
+							'[/size]'
+						);
+					}
+				);
+			}
+		},
+		color: {
+			txtExec: function (caller) {
+				var editor = this;
+
+				getEditorCommand('color')._dropDown(
+					editor,
+					caller,
+					function (color) {
+						editor.insertText(
+							'[color=' + color + ']',
+							'[/color]'
+						);
+					}
+				);
+			}
+		},
+		bulletlist: {
+			txtExec: function (caller, selected) {
+				this.insertText(
+					'[ul]\n[li]' +
+					selected.split(/\r?\n/).join('[/li]\n[li]') +
+					'[/li]\n[/ul]'
+				);
+			}
+		},
+		orderedlist: {
+			txtExec: function (caller, selected) {
+				this.insertText(
+					'[ol]\n[li]' +
+					selected.split(/\r?\n/).join('[/li]\n[li]') +
+					'[/li]\n[/ol]'
+				);
+			}
+		},
+		table: {
+			txtExec: ['[table][tr][td]', '[/td][/tr][/table]']
+		},
+		horizontalrule: {
+			txtExec: ['[hr]']
+		},
+		code: {
+			txtExec: ['[code]', '[/code]']
+		},
+		image: {
+			txtExec: function (caller, selected) {
+				var	editor  = this;
+
+				getEditorCommand('image')._dropDown(
+					editor,
+					caller,
+					selected,
+					function (url, width, height) {
+						var attrs  = '';
+
+						if (width) {
+							attrs += ' width=' + width;
+						}
+
+						if (height) {
+							attrs += ' height=' + height;
+						}
+
+						editor.insertText(
+							'[img' + attrs + ']' + url + '[/img]'
+						);
+					}
+				);
+			}
+		},
+		email: {
+			txtExec: function (caller, selected) {
+				var	editor  = this;
+
+				getEditorCommand('email')._dropDown(
+					editor,
+					caller,
+					function (url, text) {
+						editor.insertText(
+							'[email=' + url + ']' +
+								(text || selected || url) +
+							'[/email]'
+						);
+					}
+				);
+			}
+		},
+		link: {
+			txtExec: function (caller, selected) {
+				var	editor  = this;
+
+				getEditorCommand('link')._dropDown(
+					editor,
+					caller,
+					function (url, text) {
+						editor.insertText(
+							'[url=' + url + ']' +
+								(text || selected || url) +
+							'[/url]'
+						);
+					}
+				);
+			}
+		},
+		quote: {
+			txtExec: ['[quote]', '[/quote]']
+		},
+		youtube: {
+			txtExec: function (caller) {
+				var editor = this;
+
+				getEditorCommand('youtube')._dropDown(
+					editor,
+					caller,
+					function (id) {
+						editor.insertText('[youtube]' + id + '[/youtube]');
+					}
+				);
+			}
+		},
+		rtl: {
+			txtExec: ['[rtl]', '[/rtl]']
+		},
+		ltr: {
+			txtExec: ['[ltr]', '[/ltr]']
+		}
+	};
+
+	var bbcodeHandlers = {
+		// START_COMMAND: Bold
+		b: {
+			tags: {
+				b: null,
+				strong: null
+			},
+			styles: {
+				// 401 is for FF 3.5
+				'font-weight': ['bold', 'bolder', '401', '700', '800', '900']
+			},
+			format: '[b]{0}[/b]',
+			html: '<strong>{0}</strong>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Italic
+		i: {
+			tags: {
+				i: null,
+				em: null
+			},
+			styles: {
+				'font-style': ['italic', 'oblique']
+			},
+			format: '[i]{0}[/i]',
+			html: '<em>{0}</em>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Underline
+		u: {
+			tags: {
+				u: null
+			},
+			styles: {
+				'text-decoration': ['underline']
+			},
+			format: '[u]{0}[/u]',
+			html: '<u>{0}</u>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Strikethrough
+		s: {
+			tags: {
+				s: null,
+				strike: null
+			},
+			styles: {
+				'text-decoration': ['line-through']
+			},
+			format: '[s]{0}[/s]',
+			html: '<s>{0}</s>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Subscript
+		sub: {
+			tags: {
+				sub: null
+			},
+			format: '[sub]{0}[/sub]',
+			html: '<sub>{0}</sub>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Superscript
+		sup: {
+			tags: {
+				sup: null
+			},
+			format: '[sup]{0}[/sup]',
+			html: '<sup>{0}</sup>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Font
+		font: {
+			tags: {
+				font: {
+					face: null
+				}
+			},
+			styles: {
+				'font-family': null
+			},
+			quoteType: QuoteType.never,
+			format: function (element, content) {
+				var font;
+
+				if (!is(element, 'font') || !(font = attr(element, 'face'))) {
+					font = css(element, 'font-family');
+				}
+
+				return '[font=' + _stripQuotes(font) + ']' +
+					content + '[/font]';
+			},
+			html: '<font face="{defaultattr}">{0}</font>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Size
+		size: {
+			tags: {
+				font: {
+					size: null
+				}
+			},
+			styles: {
+				'font-size': null
+			},
+			format: function (element, content) {
+				var	fontSize = attr(element, 'size'),
+					size     = 2;
+
+				if (!fontSize) {
+					fontSize = css(element, 'fontSize');
+				}
+
+				// Most browsers return px value but IE returns 1-7
+				if (fontSize.indexOf('px') > -1) {
+					// convert size to an int
+					fontSize = fontSize.replace('px', '') - 0;
+
+					if (fontSize < 12) {
+						size = 1;
+					}
+					if (fontSize > 15) {
+						size = 3;
+					}
+					if (fontSize > 17) {
+						size = 4;
+					}
+					if (fontSize > 23) {
+						size = 5;
+					}
+					if (fontSize > 31) {
+						size = 6;
+					}
+					if (fontSize > 47) {
+						size = 7;
+					}
+				} else {
+					size = fontSize;
+				}
+
+				return '[size=' + size + ']' + content + '[/size]';
+			},
+			html: '<font size="{defaultattr}">{!0}</font>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Color
+		color: {
+			tags: {
+				font: {
+					color: null
+				}
+			},
+			styles: {
+				color: null
+			},
+			quoteType: QuoteType.never,
+			format: function (elm, content) {
+				var	color;
+
+				if (!is(elm, 'font') || !(color = attr(elm, 'color'))) {
+					color = elm.style.color || css(elm, 'color');
+				}
+
+				return '[color=' + _normaliseColour(color) + ']' +
+					content + '[/color]';
+			},
+			html: function (token, attrs, content) {
+				return '<font color="' +
+					escapeEntities(_normaliseColour(attrs.defaultattr), true) +
+					'">' + content + '</font>';
+			}
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Lists
+		ul: {
+			tags: {
+				ul: null
+			},
+			breakStart: true,
+			isInline: false,
+			skipLastLineBreak: true,
+			format: '[ul]{0}[/ul]',
+			html: '<ul>{0}</ul>'
+		},
+		list: {
+			breakStart: true,
+			isInline: false,
+			skipLastLineBreak: true,
+			html: '<ul>{0}</ul>'
+		},
+		ol: {
+			tags: {
+				ol: null
+			},
+			breakStart: true,
+			isInline: false,
+			skipLastLineBreak: true,
+			format: '[ol]{0}[/ol]',
+			html: '<ol>{0}</ol>'
+		},
+		li: {
+			tags: {
+				li: null
+			},
+			isInline: false,
+			closedBy: ['/ul', '/ol', '/list', '*', 'li'],
+			format: '[li]{0}[/li]',
+			html: '<li>{0}</li>'
+		},
+		'*': {
+			isInline: false,
+			closedBy: ['/ul', '/ol', '/list', '*', 'li'],
+			html: '<li>{0}</li>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Table
+		table: {
+			tags: {
+				table: null
+			},
+			isInline: false,
+			isHtmlInline: true,
+			skipLastLineBreak: true,
+			format: '[table]{0}[/table]',
+			html: '<table>{0}</table>'
+		},
+		tr: {
+			tags: {
+				tr: null
+			},
+			isInline: false,
+			skipLastLineBreak: true,
+			format: '[tr]{0}[/tr]',
+			html: '<tr>{0}</tr>'
+		},
+		th: {
+			tags: {
+				th: null
+			},
+			allowsEmpty: true,
+			isInline: false,
+			format: '[th]{0}[/th]',
+			html: '<th>{0}</th>'
+		},
+		td: {
+			tags: {
+				td: null
+			},
+			allowsEmpty: true,
+			isInline: false,
+			format: '[td]{0}[/td]',
+			html: '<td>{0}</td>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Emoticons
+		emoticon: {
+			allowsEmpty: true,
+			tags: {
+				img: {
+					src: null,
+					'data-sceditor-emoticon': null
+				}
+			},
+			format: function (element, content) {
+				return attr(element, EMOTICON_DATA_ATTR) + content;
+			},
+			html: '{0}'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Horizontal Rule
+		hr: {
+			tags: {
+				hr: null
+			},
+			allowsEmpty: true,
+			isSelfClosing: true,
+			isInline: false,
+			format: '[hr]{0}',
+			html: '<hr />'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Image
+		img: {
+			allowsEmpty: true,
+			tags: {
+				img: {
+					src: null
+				}
+			},
+			allowedChildren: ['#'],
+			quoteType: QuoteType.never,
+			format: function (element, content) {
+				var	width, height,
+					attribs   = '',
+					style     = function (name) {
+						return element.style ? element.style[name] : null;
+					};
+
+				// check if this is an emoticon image
+				if (attr(element, EMOTICON_DATA_ATTR)) {
+					return content;
+				}
+
+				width = attr(element, 'width') || style('width');
+				height = attr(element, 'height') || style('height');
+
+				// only add width and height if one is specified
+				if ((element.complete && (width || height)) ||
+					(width && height)) {
+
+					attribs = '=' + dom.width(element) + 'x' +
+						dom.height(element);
+				}
+
+				return '[img' + attribs + ']' + attr(element, 'src') + '[/img]';
+			},
+			html: function (token, attrs, content) {
+				var	undef, width, height, match,
+					attribs = '';
+
+				// handle [img width=340 height=240]url[/img]
+				width  = attrs.width;
+				height = attrs.height;
+
+				// handle [img=340x240]url[/img]
+				if (attrs.defaultattr) {
+					match = attrs.defaultattr.split(/x/i);
+
+					width  = match[0];
+					height = (match.length === 2 ? match[1] : match[0]);
+				}
+
+				if (width !== undef) {
+					attribs += ' width="' + escapeEntities(width, true) + '"';
+				}
+
+				if (height !== undef) {
+					attribs += ' height="' + escapeEntities(height, true) + '"';
+				}
+
+				return '<img' + attribs +
+					' src="' + escapeUriScheme(content) + '" />';
+			}
+		},
+		// END_COMMAND
+
+		// START_COMMAND: URL
+		url: {
+			allowsEmpty: true,
+			tags: {
+				a: {
+					href: null
+				}
+			},
+			quoteType: QuoteType.never,
+			format: function (element, content) {
+				var url = attr(element, 'href');
+
+				// make sure this link is not an e-mail,
+				// if it is return e-mail BBCode
+				if (url.substr(0, 7) === 'mailto:') {
+					return '[email="' + url.substr(7) + '"]' +
+						content + '[/email]';
+				}
+
+				return '[url=' + url + ']' + content + '[/url]';
+			},
+			html: function (token, attrs, content) {
+				attrs.defaultattr =
+					escapeEntities(attrs.defaultattr, true) || content;
+
+				return '<a href="' + escapeUriScheme(attrs.defaultattr) + '">' +
+					content + '</a>';
+			}
+		},
+		// END_COMMAND
+
+		// START_COMMAND: E-mail
+		email: {
+			quoteType: QuoteType.never,
+			html: function (token, attrs, content) {
+				return '<a href="mailto:' +
+					(escapeEntities(attrs.defaultattr, true) || content) +
+					'">' + content + '</a>';
+			}
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Quote
+		quote: {
+			tags: {
+				blockquote: null
+			},
+			isInline: false,
+			quoteType: QuoteType.never,
+			format: function (element, content) {
+				var authorAttr = 'data-author';
+				var	author = '';
+				var cite;
+				var children = element.children;
+
+				for (var i = 0; !cite && i < children.length; i++) {
+					if (is(children[i], 'cite')) {
+						cite = children[i];
+					}
+				}
+
+				if (cite || attr(element, authorAttr)) {
+					author = cite && cite.textContent ||
+						attr(element, authorAttr);
+
+					attr(element, authorAttr, author);
+
+					if (cite) {
+						element.removeChild(cite);
+					}
+
+					content	= this.elementToBbcode(element);
+					author  = '=' + author.replace(/(^\s+|\s+$)/g, '');
+
+					if (cite) {
+						element.insertBefore(cite, element.firstChild);
+					}
+				}
+
+				return '[quote' + author + ']' + content + '[/quote]';
+			},
+			html: function (token, attrs, content) {
+				if (attrs.defaultattr) {
+					content = '<cite>' + escapeEntities(attrs.defaultattr) +
+						'</cite>' + content;
+				}
+
+				return '<blockquote>' + content + '</blockquote>';
+			}
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Code
+		code: {
+			tags: {
+				code: null
+			},
+			isInline: false,
+			allowedChildren: ['#', '#newline'],
+			format: '[code]{0}[/code]',
+			html: '<code>{0}</code>'
+		},
+		// END_COMMAND
+
+
+		// START_COMMAND: Left
+		left: {
+			styles: {
+				'text-align': [
+					'left',
+					'-webkit-left',
+					'-moz-left',
+					'-khtml-left'
+				]
+			},
+			isInline: false,
+			allowsEmpty: true,
+			format: '[left]{0}[/left]',
+			html: '<div align="left">{0}</div>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Centre
+		center: {
+			styles: {
+				'text-align': [
+					'center',
+					'-webkit-center',
+					'-moz-center',
+					'-khtml-center'
+				]
+			},
+			isInline: false,
+			allowsEmpty: true,
+			format: '[center]{0}[/center]',
+			html: '<div align="center">{0}</div>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Right
+		right: {
+			styles: {
+				'text-align': [
+					'right',
+					'-webkit-right',
+					'-moz-right',
+					'-khtml-right'
+				]
+			},
+			isInline: false,
+			allowsEmpty: true,
+			format: '[right]{0}[/right]',
+			html: '<div align="right">{0}</div>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Justify
+		justify: {
+			styles: {
+				'text-align': [
+					'justify',
+					'-webkit-justify',
+					'-moz-justify',
+					'-khtml-justify'
+				]
+			},
+			isInline: false,
+			allowsEmpty: true,
+			format: '[justify]{0}[/justify]',
+			html: '<div align="justify">{0}</div>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: YouTube
+		youtube: {
+			allowsEmpty: true,
+			tags: {
+				iframe: {
+					'data-youtube-id': null
+				}
+			},
+			format: function (element, content) {
+				element = attr(element, 'data-youtube-id');
+
+				return element ? '[youtube]' + element + '[/youtube]' : content;
+			},
+			html: '<iframe width="560" height="315" frameborder="0" ' +
+				'src="https://www.youtube-nocookie.com/embed/{0}?wmode=opaque" ' +
+				'data-youtube-id="{0}" allowfullscreen></iframe>'
+		},
+		// END_COMMAND
+
+
+		// START_COMMAND: Rtl
+		rtl: {
+			styles: {
+				direction: ['rtl']
+			},
+			isInline: false,
+			format: '[rtl]{0}[/rtl]',
+			html: '<div style="direction: rtl">{0}</div>'
+		},
+		// END_COMMAND
+
+		// START_COMMAND: Ltr
+		ltr: {
+			styles: {
+				direction: ['ltr']
+			},
+			isInline: false,
+			format: '[ltr]{0}[/ltr]',
+			html: '<div style="direction: ltr">{0}</div>'
+		},
+		// END_COMMAND
+
+		// this is here so that commands above can be removed
+		// without having to remove the , after the last one.
+		// Needed for IE.
+		ignore: {}
+	};
+
+	/**
+	 * Formats a string replacing {name} with the values of
+	 * obj.name properties.
+	 *
+	 * If there is no property for the specified {name} then
+	 * it will be left intact.
+	 *
+	 * @param  {string} str
+	 * @param  {Object} obj
+	 * @return {string}
+	 * @since 2.0.0
+	 */
+	function formatBBCodeString(str, obj) {
+		return str.replace(/\{([^}]+)\}/g, function (match, group) {
+			var	undef,
+				escape = true;
+
+			if (group.charAt(0) === '!') {
+				escape = false;
+				group = group.substring(1);
+			}
+
+			if (group === '0') {
+				escape = false;
+			}
+
+			if (obj[group] === undef) {
+				return match;
+			}
+
+			return escape ? escapeEntities(obj[group], true) : obj[group];
+		});
+	}
+
+	function isFunction(fn) {
+		return typeof fn === 'function';
+	}
+
+	/**
+	 * Removes any leading or trailing quotes ('")
+	 *
+	 * @return string
+	 * @since v1.4.0
+	 */
+	function _stripQuotes(str) {
+		return str ?
+			str.replace(/\\(.)/g, '$1').replace(/^(["'])(.*?)\1$/, '$2') : str;
+	}
+
+	/**
+	 * Formats a string replacing {0}, {1}, {2}, ect. with
+	 * the params provided
+	 *
+	 * @param {string} str The string to format
+	 * @param {...string} arg The strings to replace
+	 * @return {string}
+	 * @since v1.4.0
+	 */
+	function _formatString(str) {
+		var	undef;
+		var args = arguments;
+
+		return str.replace(/\{(\d+)\}/g, function (_, matchNum) {
+			return args[matchNum - 0 + 1] !== undef ?
+				args[matchNum - 0 + 1] :
+				'{' + matchNum + '}';
+		});
+	}
+
+	var TOKEN_OPEN = 'open';
+	var TOKEN_CONTENT = 'content';
+	var TOKEN_NEWLINE = 'newline';
+	var TOKEN_CLOSE = 'close';
+
+
+	/*
+	 * @typedef {Object} TokenizeToken
+	 * @property {string} type
+	 * @property {string} name
+	 * @property {string} val
+	 * @property {Object.<string, string>} attrs
+	 * @property {array} children
+	 * @property {TokenizeToken} closing
+	 */
+
+	/**
+	 * Tokenize token object
+	 *
+	 * @param  {string} type The type of token this is,
+	 *                       should be one of tokenType
+	 * @param  {string} name The name of this token
+	 * @param  {string} val The originally matched string
+	 * @param  {array} attrs Any attributes. Only set on
+	 *                       TOKEN_TYPE_OPEN tokens
+	 * @param  {array} children Any children of this token
+	 * @param  {TokenizeToken} closing This tokens closing tag.
+	 *                                 Only set on TOKEN_TYPE_OPEN tokens
+	 * @class {TokenizeToken}
+	 * @name {TokenizeToken}
+	 * @memberOf BBCodeParser.prototype
+	 */
+	// eslint-disable-next-line max-params
+	function TokenizeToken(type, name, val, attrs, children, closing) {
+		var base      = this;
+
+		base.type     = type;
+		base.name     = name;
+		base.val      = val;
+		base.attrs    = attrs || {};
+		base.children = children || [];
+		base.closing  = closing || null;
+	};
+
+	TokenizeToken.prototype = {
+		/** @lends BBCodeParser.prototype.TokenizeToken */
+		/**
+		 * Clones this token
+		 *
+		 * @return {TokenizeToken}
+		 */
+		clone: function () {
+			var base = this;
+
+			return new TokenizeToken(
+				base.type,
+				base.name,
+				base.val,
+				extend({}, base.attrs),
+				[],
+				base.closing ? base.closing.clone() : null
+			);
+		},
+		/**
+		 * Splits this token at the specified child
+		 *
+		 * @param  {TokenizeToken} splitAt The child to split at
+		 * @return {TokenizeToken} The right half of the split token or
+		 *                         empty clone if invalid splitAt lcoation
+		 */
+		splitAt: function (splitAt) {
+			var offsetLength;
+			var base         = this;
+			var	clone        = base.clone();
+			var offset       = base.children.indexOf(splitAt);
+
+			if (offset > -1) {
+				// Work out how many items are on the right side of the split
+				// to pass to splice()
+				offsetLength   = base.children.length - offset;
+				clone.children = base.children.splice(offset, offsetLength);
+			}
+
+			return clone;
+		}
+	};
+
+
+	/**
+	 * SCEditor BBCode parser class
+	 *
+	 * @param {Object} options
+	 * @class BBCodeParser
+	 * @name BBCodeParser
+	 * @since v1.4.0
+	 */
+	function BBCodeParser(options) {
+		var base = this;
+
+		base.opts = extend({}, BBCodeParser.defaults, options);
+
+		/**
+		 * Takes a BBCode string and splits it into open,
+		 * content and close tags.
+		 *
+		 * It does no checking to verify a tag has a matching open
+		 * or closing tag or if the tag is valid child of any tag
+		 * before it. For that the tokens should be passed to the
+		 * parse function.
+		 *
+		 * @param {string} str
+		 * @return {array}
+		 * @memberOf BBCodeParser.prototype
+		 */
+		base.tokenize = function (str) {
+			var	matches, type, i;
+			var tokens = [];
+			// The token types in reverse order of precedence
+			// (they're looped in reverse)
+			var tokenTypes = [
+				{
+					type: TOKEN_CONTENT,
+					regex: /^([^\[\r\n]+|\[)/
+				},
+				{
+					type: TOKEN_NEWLINE,
+					regex: /^(\r\n|\r|\n)/
+				},
+				{
+					type: TOKEN_OPEN,
+					regex: /^\[[^\[\]]+\]/
+				},
+				// Close must come before open as they are
+				// the same except close has a / at the start.
+				{
+					type: TOKEN_CLOSE,
+					regex: /^\[\/[^\[\]]+\]/
+				}
+			];
+
+			strloop:
+			while (str.length) {
+				i = tokenTypes.length;
+				while (i--) {
+					type = tokenTypes[i].type;
+
+					// Check if the string matches any of the tokens
+					if (!(matches = str.match(tokenTypes[i].regex)) ||
+						!matches[0]) {
+						continue;
+					}
+
+					// Add the match to the tokens list
+					tokens.push(tokenizeTag(type, matches[0]));
+
+					// Remove the match from the string
+					str = str.substr(matches[0].length);
+
+					// The token has been added so start again
+					continue strloop;
+				}
+
+				// If there is anything left in the string which doesn't match
+				// any of the tokens then just assume it's content and add it.
+				if (str.length) {
+					tokens.push(tokenizeTag(TOKEN_CONTENT, str));
+				}
+
+				str = '';
+			}
+
+			return tokens;
+		};
+
+		/**
+		 * Extracts the name an params from a tag
+		 *
+		 * @param {string} type
+		 * @param {string} val
+		 * @return {Object}
+		 * @private
+		 */
+		function tokenizeTag(type, val) {
+			var matches, attrs, name,
+				openRegex  = /\[([^\]\s=]+)(?:([^\]]+))?\]/,
+				closeRegex = /\[\/([^\[\]]+)\]/;
+
+			// Extract the name and attributes from opening tags and
+			// just the name from closing tags.
+			if (type === TOKEN_OPEN && (matches = val.match(openRegex))) {
+				name = lower(matches[1]);
+
+				if (matches[2] && (matches[2] = matches[2].trim())) {
+					attrs = tokenizeAttrs(matches[2]);
+				}
+			}
+
+			if (type === TOKEN_CLOSE &&
+				(matches = val.match(closeRegex))) {
+				name = lower(matches[1]);
+			}
+
+			if (type === TOKEN_NEWLINE) {
+				name = '#newline';
+			}
+
+			// Treat all tokens without a name and
+			// all unknown BBCodes as content
+			if (!name || ((type === TOKEN_OPEN || type === TOKEN_CLOSE) &&
+				!bbcodeHandlers[name])) {
+
+				type = TOKEN_CONTENT;
+				name = '#';
+			}
+
+			return new TokenizeToken(type, name, val, attrs);
+		}
+
+		/**
+		 * Extracts the individual attributes from a string containing
+		 * all the attributes.
+		 *
+		 * @param {string} attrs
+		 * @return {Object} Assoc array of attributes
+		 * @private
+		 */
+		function tokenizeAttrs(attrs) {
+			var	matches,
+				/*
+				([^\s=]+)				Anything that's not a space or equals
+				=						Equals sign =
+				(?:
+					(?:
+						(["'])					The opening quote
+						(
+							(?:\\\2|[^\2])*?	Anything that isn't the
+												unescaped opening quote
+						)
+						\2						The opening quote again which
+												will close the string
+					)
+						|				If not a quoted string then match
+					(
+						(?:.(?!\s\S+=))*.?		Anything that isn't part of
+												[space][non-space][=] which
+												would be a new attribute
+					)
+				)
+				*/
+				attrRegex = /([^\s=]+)=(?:(?:(["'])((?:\\\2|[^\2])*?)\2)|((?:.(?!\s\S+=))*.))/g,
+				ret       = {};
+
+			// if only one attribute then remove the = from the start and
+			// strip any quotes
+			if (attrs.charAt(0) === '=' && attrs.indexOf('=', 1) < 0) {
+				ret.defaultattr = _stripQuotes(attrs.substr(1));
+			} else {
+				if (attrs.charAt(0) === '=') {
+					attrs = 'defaultattr' + attrs;
+				}
+
+				// No need to strip quotes here, the regex will do that.
+				while ((matches = attrRegex.exec(attrs))) {
+					ret[lower(matches[1])] =
+						_stripQuotes(matches[3]) || matches[4];
+				}
+			}
+
+			return ret;
+		}
+
+		/**
+		 * Parses a string into an array of BBCodes
+		 *
+		 * @param  {string}  str
+		 * @param  {boolean} preserveNewLines If to preserve all new lines, not
+		 *                                    strip any based on the passed
+		 *                                    formatting options
+		 * @return {array}                    Array of BBCode objects
+		 * @memberOf BBCodeParser.prototype
+		 */
+		base.parse = function (str, preserveNewLines) {
+			var ret  = parseTokens(base.tokenize(str));
+			var opts = base.opts;
+
+			if (opts.fixInvalidNesting) {
+				fixNesting(ret);
+			}
+
+			normaliseNewLines(ret, null, preserveNewLines);
+
+			if (opts.removeEmptyTags) {
+				removeEmpty(ret);
+			}
+
+			return ret;
+		};
+
+		/**
+		 * Checks if an array of TokenizeToken's contains the
+		 * specified token.
+		 *
+		 * Checks the tokens name and type match another tokens
+		 * name and type in the array.
+		 *
+		 * @param  {string}    name
+		 * @param  {string} type
+		 * @param  {array}     arr
+		 * @return {Boolean}
+		 * @private
+		 */
+		function hasTag(name, type, arr) {
+			var i = arr.length;
+
+			while (i--) {
+				if (arr[i].type === type && arr[i].name === name) {
+					return true;
+				}
+			}
+
+			return false;
+		}
+
+		/**
+		 * Checks if the child tag is allowed as one
+		 * of the parent tags children.
+		 *
+		 * @param  {TokenizeToken}  parent
+		 * @param  {TokenizeToken}  child
+		 * @return {Boolean}
+		 * @private
+		 */
+		function isChildAllowed(parent, child) {
+			var	parentBBCode    = parent ? bbcodeHandlers[parent.name] : {},
+				allowedChildren = parentBBCode.allowedChildren;
+
+			if (base.opts.fixInvalidChildren && allowedChildren) {
+				return allowedChildren.indexOf(child.name || '#') > -1;
+			}
+
+			return true;
+		}
+
+		// TODO: Tidy this parseTokens() function up a bit.
+		/**
+		 * Parses an array of tokens created by tokenize()
+		 *
+		 * @param  {array} toks
+		 * @return {array} Parsed tokens
+		 * @see tokenize()
+		 * @private
+		 */
+		function parseTokens(toks) {
+			var	token, bbcode, curTok, clone, i, next,
+				cloned     = [],
+				output     = [],
+				openTags   = [],
+				/**
+				 * Returns the currently open tag or undefined
+				 * @return {TokenizeToken}
+				 */
+				currentTag = function () {
+					return last(openTags);
+				},
+				/**
+				 * Adds a tag to either the current tags children
+				 * or to the output array.
+				 * @param {TokenizeToken} token
+				 * @private
+				 */
+				addTag = function (token) {
+					if (currentTag()) {
+						currentTag().children.push(token);
+					} else {
+						output.push(token);
+					}
+				},
+				/**
+				 * Checks if this tag closes the current tag
+				 * @param  {string} name
+				 * @return {Void}
+				 */
+				closesCurrentTag = function (name) {
+					return currentTag() &&
+						(bbcode = bbcodeHandlers[currentTag().name]) &&
+						bbcode.closedBy &&
+						bbcode.closedBy.indexOf(name) > -1;
+				};
+
+			while ((token = toks.shift())) {
+				next = toks[0];
+
+				/*
+				 * Fixes any invalid children.
+				 *
+				 * If it is an element which isn't allowed as a child of it's
+				 * parent then it will be converted to content of the parent
+				 * element. i.e.
+				 *     [code]Code [b]only[/b] allows text.[/code]
+				 * Will become:
+				 *     <code>Code [b]only[/b] allows text.</code>
+				 * Instead of:
+				 *     <code>Code <b>only</b> allows text.</code>
+				 */
+				// Ignore tags that can't be children
+				if (!isChildAllowed(currentTag(), token)) {
+
+					// exclude closing tags of current tag
+					if (token.type !== TOKEN_CLOSE || !currentTag() ||
+							token.name !== currentTag().name) {
+						token.name = '#';
+						token.type = TOKEN_CONTENT;
+					}
+				}
+
+				switch (token.type) {
+					case TOKEN_OPEN:
+						// Check it this closes a parent,
+						// e.g. for lists [*]one [*]two
+						if (closesCurrentTag(token.name)) {
+							openTags.pop();
+						}
+
+						addTag(token);
+						bbcode = bbcodeHandlers[token.name];
+
+						// If this tag is not self closing and it has a closing
+						// tag then it is open and has children so add it to the
+						// list of open tags. If has the closedBy property then
+						// it is closed by other tags so include everything as
+						// it's children until one of those tags is reached.
+						if (bbcode && !bbcode.isSelfClosing &&
+							(bbcode.closedBy ||
+								hasTag(token.name, TOKEN_CLOSE, toks))) {
+							openTags.push(token);
+						} else if (!bbcode || !bbcode.isSelfClosing) {
+							token.type = TOKEN_CONTENT;
+						}
+						break;
+
+					case TOKEN_CLOSE:
+						// check if this closes the current tag,
+						// e.g. [/list] would close an open [*]
+						if (currentTag() && token.name !== currentTag().name &&
+							closesCurrentTag('/' + token.name)) {
+
+							openTags.pop();
+						}
+
+						// If this is closing the currently open tag just pop
+						// the close tag off the open tags array
+						if (currentTag() && token.name === currentTag().name) {
+							currentTag().closing = token;
+							openTags.pop();
+
+						// If this is closing an open tag that is the parent of
+						// the current tag then clone all the tags including the
+						// current one until reaching the parent that is being
+						// closed. Close the parent and then add the clones back
+						// in.
+						} else if (hasTag(token.name, TOKEN_OPEN, openTags)) {
+
+							// Remove the tag from the open tags
+							while ((curTok = openTags.pop())) {
+
+								// If it's the tag that is being closed then
+								// discard it and break the loop.
+								if (curTok.name === token.name) {
+									curTok.closing = token;
+									break;
+								}
+
+								// Otherwise clone this tag and then add any
+								// previously cloned tags as it's children
+								clone = curTok.clone();
+
+								if (cloned.length) {
+									clone.children.push(last(cloned));
+								}
+
+								cloned.push(clone);
+							}
+
+							// Place block linebreak before cloned tags
+							if (next && next.type === TOKEN_NEWLINE) {
+								bbcode = bbcodeHandlers[token.name];
+								if (bbcode && bbcode.isInline === false) {
+									addTag(next);
+									toks.shift();
+								}
+							}
+
+							// Add the last cloned child to the now current tag
+							// (the parent of the tag which was being closed)
+							addTag(last(cloned));
+
+							// Add all the cloned tags to the open tags list
+							i = cloned.length;
+							while (i--) {
+								openTags.push(cloned[i]);
+							}
+
+							cloned.length = 0;
+
+						// This tag is closing nothing so treat it as content
+						} else {
+							token.type = TOKEN_CONTENT;
+							addTag(token);
+						}
+						break;
+
+					case TOKEN_NEWLINE:
+						// handle things like
+						//     [*]list\nitem\n[*]list1
+						// where it should come out as
+						//     [*]list\nitem[/*]\n[*]list1[/*]
+						// instead of
+						//     [*]list\nitem\n[/*][*]list1[/*]
+						if (currentTag() && next && closesCurrentTag(
+							(next.type === TOKEN_CLOSE ? '/' : '') +
+							next.name
+						)) {
+							// skip if the next tag is the closing tag for
+							// the option tag, i.e. [/*]
+							if (!(next.type === TOKEN_CLOSE &&
+								next.name === currentTag().name)) {
+								bbcode = bbcodeHandlers[currentTag().name];
+
+								if (bbcode && bbcode.breakAfter) {
+									openTags.pop();
+								} else if (bbcode &&
+									bbcode.isInline === false &&
+									base.opts.breakAfterBlock &&
+									bbcode.breakAfter !== false) {
+									openTags.pop();
+								}
+							}
+						}
+
+						addTag(token);
+						break;
+
+					default: // content
+						addTag(token);
+						break;
+				}
+			}
+
+			return output;
+		}
+
+		/**
+		 * Normalise all new lines
+		 *
+		 * Removes any formatting new lines from the BBCode
+		 * leaving only content ones. I.e. for a list:
+		 *
+		 * [list]
+		 * [*] list item one
+		 * with a line break
+		 * [*] list item two
+		 * [/list]
+		 *
+		 * would become
+		 *
+		 * [list] [*] list item one
+		 * with a line break [*] list item two [/list]
+		 *
+		 * Which makes it easier to convert to HTML or add
+		 * the formatting new lines back in when converting
+		 * back to BBCode
+		 *
+		 * @param  {array} children
+		 * @param  {TokenizeToken} parent
+		 * @param  {boolean} onlyRemoveBreakAfter
+		 * @return {void}
+		 */
+		function normaliseNewLines(children, parent, onlyRemoveBreakAfter) {
+			var	token, left, right, parentBBCode, bbcode,
+				removedBreakEnd, removedBreakBefore, remove;
+			var childrenLength = children.length;
+			// TODO: this function really needs tidying up
+			if (parent) {
+				parentBBCode = bbcodeHandlers[parent.name];
+			}
+
+			var i = childrenLength;
+			while (i--) {
+				if (!(token = children[i])) {
+					continue;
+				}
+
+				if (token.type === TOKEN_NEWLINE) {
+					left   = i > 0 ? children[i - 1] : null;
+					right  = i < childrenLength - 1 ? children[i + 1] : null;
+					remove = false;
+
+					// Handle the start and end new lines
+					// e.g. [tag]\n and \n[/tag]
+					if (!onlyRemoveBreakAfter && parentBBCode &&
+						parentBBCode.isSelfClosing !== true) {
+						// First child of parent so must be opening line break
+						// (breakStartBlock, breakStart) e.g. [tag]\n
+						if (!left) {
+							if (parentBBCode.isInline === false &&
+								base.opts.breakStartBlock &&
+								parentBBCode.breakStart !== false) {
+								remove = true;
+							}
+
+							if (parentBBCode.breakStart) {
+								remove = true;
+							}
+						// Last child of parent so must be end line break
+						// (breakEndBlock, breakEnd)
+						// e.g. \n[/tag]
+						// remove last line break (breakEndBlock, breakEnd)
+						} else if (!removedBreakEnd && !right) {
+							if (parentBBCode.isInline === false &&
+								base.opts.breakEndBlock &&
+								parentBBCode.breakEnd !== false) {
+								remove = true;
+							}
+
+							if (parentBBCode.breakEnd) {
+								remove = true;
+							}
+
+							removedBreakEnd = remove;
+						}
+					}
+
+					if (left && left.type === TOKEN_OPEN) {
+						if ((bbcode = bbcodeHandlers[left.name])) {
+							if (!onlyRemoveBreakAfter) {
+								if (bbcode.isInline === false &&
+									base.opts.breakAfterBlock &&
+									bbcode.breakAfter !== false) {
+									remove = true;
+								}
+
+								if (bbcode.breakAfter) {
+									remove = true;
+								}
+							} else if (bbcode.isInline === false) {
+								remove = true;
+							}
+						}
+					}
+
+					if (!onlyRemoveBreakAfter && !removedBreakBefore &&
+						right && right.type === TOKEN_OPEN) {
+
+						if ((bbcode = bbcodeHandlers[right.name])) {
+							if (bbcode.isInline === false &&
+								base.opts.breakBeforeBlock &&
+								bbcode.breakBefore !== false) {
+								remove = true;
+							}
+
+							if (bbcode.breakBefore) {
+								remove = true;
+							}
+
+							removedBreakBefore = remove;
+
+							if (remove) {
+								children.splice(i, 1);
+								continue;
+							}
+						}
+					}
+
+					if (remove) {
+						children.splice(i, 1);
+					}
+
+					// reset double removedBreakBefore removal protection.
+					// This is needed for cases like \n\n[\tag] where
+					// only 1 \n should be removed but without this they both
+					// would be.
+					removedBreakBefore = false;
+				} else if (token.type === TOKEN_OPEN) {
+					normaliseNewLines(token.children, token,
+						onlyRemoveBreakAfter);
+				}
+			}
+		}
+
+		/**
+		 * Fixes any invalid nesting.
+		 *
+		 * If it is a block level element inside 1 or more inline elements
+		 * then those inline elements will be split at the point where the
+		 * block level is and the block level element placed between the split
+		 * parts. i.e.
+		 *     [inline]A[blocklevel]B[/blocklevel]C[/inline]
+		 * Will become:
+		 *     [inline]A[/inline][blocklevel]B[/blocklevel][inline]C[/inline]
+		 *
+		 * @param {array} children
+		 * @param {array} [parents] Null if there is no parents
+		 * @param {boolea} [insideInline] If inside an inline element
+		 * @param {array} [rootArr] Root array if there is one
+		 * @return {array}
+		 * @private
+		 */
+		function fixNesting(children, parents, insideInline, rootArr) {
+			var	token, i, parent, parentIndex, parentParentChildren, right;
+
+			var isInline = function (token) {
+				var bbcode = bbcodeHandlers[token.name];
+
+				return !bbcode || bbcode.isInline !== false;
+			};
+
+			parents = parents || [];
+			rootArr = rootArr || children;
+
+			// This must check the length each time as it can change when
+			// tokens are moved to fix the nesting.
+			for (i = 0; i < children.length; i++) {
+				if (!(token = children[i]) || token.type !== TOKEN_OPEN) {
+					continue;
+				}
+
+				if (insideInline && !isInline(token)) {
+					// if this is a blocklevel element inside an inline one then
+					// split the parent at the block level element
+					parent = last(parents);
+					right  = parent.splitAt(token);
+
+					parentParentChildren = parents.length > 1 ?
+						parents[parents.length - 2].children : rootArr;
+
+					// If parent inline is allowed inside this tag, clone it and
+					// wrap this tags children in it.
+					if (isChildAllowed(token, parent)) {
+						var clone = parent.clone();
+						clone.children = token.children;
+						token.children = [clone];
+					}
+
+					parentIndex = parentParentChildren.indexOf(parent);
+					if (parentIndex > -1) {
+						// remove the block level token from the right side of
+						// the split inline element
+						right.children.splice(0, 1);
+
+						// insert the block level token and the right side after
+						// the left side of the inline token
+						parentParentChildren.splice(
+							parentIndex + 1, 0, token, right
+						);
+
+						// If token is a block and is followed by a newline,
+						// then move the newline along with it to the new parent
+						var next = right.children[0];
+						if (next && next.type === TOKEN_NEWLINE) {
+							if (!isInline(token)) {
+								right.children.splice(0, 1);
+								parentParentChildren.splice(
+									parentIndex + 2, 0, next
+								);
+							}
+						}
+
+						// return to parents loop as the
+						// children have now increased
+						return;
+					}
+
+				}
+
+				parents.push(token);
+
+				fixNesting(
+					token.children,
+					parents,
+					insideInline || isInline(token),
+					rootArr
+				);
+
+				parents.pop();
+			}
+		}
+
+		/**
+		 * Removes any empty BBCodes which are not allowed to be empty.
+		 *
+		 * @param {array} tokens
+		 * @private
+		 */
+		function removeEmpty(tokens) {
+			var	token, bbcode;
+
+			/**
+			 * Checks if all children are whitespace or not
+			 * @private
+			 */
+			var isTokenWhiteSpace = function (children) {
+				var j = children.length;
+
+				while (j--) {
+					var type = children[j].type;
+
+					if (type === TOKEN_OPEN || type === TOKEN_CLOSE) {
+						return false;
+					}
+
+					if (type === TOKEN_CONTENT &&
+						/\S|\u00A0/.test(children[j].val)) {
+						return false;
+					}
+				}
+
+				return true;
+			};
+
+			var i = tokens.length;
+			while (i--) {
+				// So skip anything that isn't a tag since only tags can be
+				// empty, content can't
+				if (!(token = tokens[i]) || token.type !== TOKEN_OPEN) {
+					continue;
+				}
+
+				bbcode = bbcodeHandlers[token.name];
+
+				// Remove any empty children of this tag first so that if they
+				// are all removed this one doesn't think it's not empty.
+				removeEmpty(token.children);
+
+				if (isTokenWhiteSpace(token.children) && bbcode &&
+					!bbcode.isSelfClosing && !bbcode.allowsEmpty) {
+					tokens.splice.apply(tokens, [i, 1].concat(token.children));
+				}
+			}
+		}
+
+		/**
+		 * Converts a BBCode string to HTML
+		 *
+		 * @param {string} str
+		 * @param {boolean}   preserveNewLines If to preserve all new lines, not
+		 *                                  strip any based on the passed
+		 *                                  formatting options
+		 * @return {string}
+		 * @memberOf BBCodeParser.prototype
+		 */
+		base.toHTML = function (str, preserveNewLines) {
+			return convertToHTML(base.parse(str, preserveNewLines), true);
+		};
+
+		base.toHTMLFragment = function (str, preserveNewLines) {
+			return convertToHTML(base.parse(str, preserveNewLines), false);
+		};
+
+		/**
+		 * @private
+		 */
+		function convertToHTML(tokens, isRoot) {
+			var	undef, token, bbcode, content, html, needsBlockWrap,
+				blockWrapOpen, isInline, lastChild,
+				ret = '';
+
+			isInline = function (bbcode) {
+				return (!bbcode || (bbcode.isHtmlInline !== undef ?
+					bbcode.isHtmlInline : bbcode.isInline)) !== false;
+			};
+
+			while (tokens.length > 0) {
+				if (!(token = tokens.shift())) {
+					continue;
+				}
+
+				if (token.type === TOKEN_OPEN) {
+					lastChild = token.children[token.children.length - 1] || {};
+					bbcode = bbcodeHandlers[token.name];
+					needsBlockWrap = isRoot && isInline(bbcode);
+					content = convertToHTML(token.children, false);
+
+					if (bbcode && bbcode.html) {
+						// Only add a line break to the end if this is
+						// blocklevel and the last child wasn't block-level
+						if (!isInline(bbcode) &&
+							isInline(bbcodeHandlers[lastChild.name]) &&
+							!bbcode.isPreFormatted &&
+							!bbcode.skipLastLineBreak) {
+							// Add placeholder br to end of block level
+							// elements
+							content += '<br />';
+						}
+
+						// Visman - удалить под одной пустой строке в начале и конце содержимого
+						content = content.replace(/^\x20*<br \/>/, '').replace(/<br \/>\x20*$/, '');
+
+						if (!isFunction(bbcode.html)) {
+							token.attrs['0'] = content;
+							html = formatBBCodeString(
+								bbcode.html,
+								token.attrs
+							);
+						} else {
+							html = bbcode.html.call(
+								base,
+								token,
+								token.attrs,
+								content
+							);
+						}
+					} else {
+						html = token.val + content +
+							(token.closing ? token.closing.val : '');
+					}
+				} else if (token.type === TOKEN_NEWLINE) {
+					if (!isRoot) {
+						ret += '<br />';
+						continue;
+					}
+
+					// If not already in a block wrap then start a new block
+					if (!blockWrapOpen) {
+						ret += '<div>';
+					}
+
+					ret += '<br />';
+
+					// Normally the div acts as a line-break with by moving
+					// whatever comes after onto a new line.
+					// If this is the last token, add an extra line-break so it
+					// shows as there will be nothing after it.
+					if (!tokens.length) {
+						ret += '<br />';
+					}
+
+					ret += '</div>\n';
+					blockWrapOpen = false;
+					continue;
+				// content
+				} else {
+					needsBlockWrap = isRoot;
+					html           = escapeEntities(token.val, true);
+				}
+
+				if (needsBlockWrap && !blockWrapOpen) {
+					ret += '<div>';
+					blockWrapOpen = true;
+				} else if (!needsBlockWrap && blockWrapOpen) {
+					ret += '</div>\n';
+					blockWrapOpen = false;
+				}
+
+				ret += html;
+			}
+
+			if (blockWrapOpen) {
+				ret += '</div>\n';
+			}
+
+			return ret;
+		}
+
+		/**
+		 * Takes a BBCode string, parses it then converts it back to BBCode.
+		 *
+		 * This will auto fix the BBCode and format it with the specified
+		 * options.
+		 *
+		 * @param {string} str
+		 * @param {boolean} preserveNewLines If to preserve all new lines, not
+		 *                                strip any based on the passed
+		 *                                formatting options
+		 * @return {string}
+		 * @memberOf BBCodeParser.prototype
+		 */
+		base.toBBCode = function (str, preserveNewLines) {
+			return convertToBBCode(base.parse(str, preserveNewLines));
+		};
+
+		/**
+		 * Converts parsed tokens back into BBCode with the
+		 * formatting specified in the options and with any
+		 * fixes specified.
+		 *
+		 * @param  {array} toks Array of parsed tokens from base.parse()
+		 * @return {string}
+		 * @private
+		 */
+		function convertToBBCode(toks) {
+			var	token, attr, bbcode, isBlock, isSelfClosing, quoteType,
+				breakBefore, breakStart, breakEnd, breakAfter,
+				ret = '';
+
+			while (toks.length > 0) {
+				if (!(token = toks.shift())) {
+					continue;
+				}
+				// TODO: tidy this
+				bbcode        = bbcodeHandlers[token.name];
+				isBlock       = !(!bbcode || bbcode.isInline !== false);
+				isSelfClosing = bbcode && bbcode.isSelfClosing;
+
+				breakBefore = (isBlock && base.opts.breakBeforeBlock &&
+						bbcode.breakBefore !== false) ||
+					(bbcode && bbcode.breakBefore);
+
+				breakStart = (isBlock && !isSelfClosing &&
+						base.opts.breakStartBlock &&
+						bbcode.breakStart !== false) ||
+					(bbcode && bbcode.breakStart);
+
+				breakEnd = (isBlock && base.opts.breakEndBlock &&
+						bbcode.breakEnd !== false) ||
+					(bbcode && bbcode.breakEnd);
+
+				breakAfter = (isBlock && base.opts.breakAfterBlock &&
+						bbcode.breakAfter !== false) ||
+					(bbcode && bbcode.breakAfter);
+
+				quoteType = (bbcode ? bbcode.quoteType : null) ||
+					base.opts.quoteType || QuoteType.auto;
+
+				if (!bbcode && token.type === TOKEN_OPEN) {
+					ret += token.val;
+
+					if (token.children) {
+						ret += convertToBBCode(token.children);
+					}
+
+					if (token.closing) {
+						ret += token.closing.val;
+					}
+				} else if (token.type === TOKEN_OPEN) {
+					if (breakBefore) {
+						ret += '\n';
+					}
+
+					// Convert the tag and it's attributes to BBCode
+					ret += '[' + token.name;
+					if (token.attrs) {
+						if (token.attrs.defaultattr) {
+							ret += '=' + quote(
+								token.attrs.defaultattr,
+								quoteType,
+								'defaultattr'
+							);
+
+							delete token.attrs.defaultattr;
+						}
+
+						for (attr in token.attrs) {
+							if (token.attrs.hasOwnProperty(attr)) {
+								ret += ' ' + attr + '=' +
+									quote(token.attrs[attr], quoteType, attr);
+							}
+						}
+					}
+					ret += ']';
+
+					if (breakStart) {
+						ret += '\n';
+					}
+
+					// Convert the tags children to BBCode
+					if (token.children) {
+						ret += convertToBBCode(token.children);
+					}
+
+					// add closing tag if not self closing
+					if (!isSelfClosing && !bbcode.excludeClosing) {
+						if (breakEnd) {
+							ret += '\n';
+						}
+
+						ret += '[/' + token.name + ']';
+					}
+
+					if (breakAfter) {
+						ret += '\n';
+					}
+
+					// preserve whatever was recognized as the
+					// closing tag if it is a self closing tag
+					if (token.closing && isSelfClosing) {
+						ret += token.closing.val;
+					}
+				} else {
+					ret += token.val;
+				}
+			}
+
+			return ret;
+		}
+
+		/**
+		 * Quotes an attribute
+		 *
+		 * @param {string} str
+		 * @param {BBCodeParser.QuoteType} quoteType
+		 * @param {string} name
+		 * @return {string}
+		 * @private
+		 */
+		function quote(str, quoteType, name) {
+			var	needsQuotes = /\s|=/.test(str);
+
+			if (isFunction(quoteType)) {
+				return quoteType(str, name);
+			}
+
+			if (quoteType === QuoteType.never ||
+				(quoteType === QuoteType.auto && !needsQuotes)) {
+				return str;
+			}
+
+			return '"' + str.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
+		}
+
+		/**
+		 * Returns the last element of an array or null
+		 *
+		 * @param {array} arr
+		 * @return {Object} Last element
+		 * @private
+		 */
+		function last(arr) {
+			if (arr.length) {
+				return arr[arr.length - 1];
+			}
+
+			return null;
+		}
+
+		/**
+		 * Converts a string to lowercase.
+		 *
+		 * @param {string} str
+		 * @return {string} Lowercase version of str
+		 * @private
+		 */
+		function lower(str) {
+			return str.toLowerCase();
+		}
+	};
+
+	/**
+	 * Quote type
+	 * @type {Object}
+	 * @class QuoteType
+	 * @name BBCodeParser.QuoteType
+	 * @since 1.4.0
+	 */
+	BBCodeParser.QuoteType = QuoteType;
+
+	/**
+	 * Default BBCode parser options
+	 * @type {Object}
+	 */
+	BBCodeParser.defaults = {
+		/**
+		 * If to add a new line before block level elements
+		 *
+		 * @type {Boolean}
+		 */
+		breakBeforeBlock: false,
+
+		/**
+		 * If to add a new line after the start of block level elements
+		 *
+		 * @type {Boolean}
+		 */
+		breakStartBlock: false,
+
+		/**
+		 * If to add a new line before the end of block level elements
+		 *
+		 * @type {Boolean}
+		 */
+		breakEndBlock: false,
+
+		/**
+		 * If to add a new line after block level elements
+		 *
+		 * @type {Boolean}
+		 */
+		breakAfterBlock: true,
+
+		/**
+		 * If to remove empty tags
+		 *
+		 * @type {Boolean}
+		 */
+		removeEmptyTags: true,
+
+		/**
+		 * If to fix invalid nesting,
+		 * i.e. block level elements inside inline elements.
+		 *
+		 * @type {Boolean}
+		 */
+		fixInvalidNesting: true,
+
+		/**
+		 * If to fix invalid children.
+		 * i.e. A tag which is inside a parent that doesn't
+		 * allow that type of tag.
+		 *
+		 * @type {Boolean}
+		 */
+		fixInvalidChildren: true,
+
+		/**
+		 * Attribute quote type
+		 *
+		 * @type {BBCodeParser.QuoteType}
+		 * @since 1.4.1
+		 */
+		quoteType: QuoteType.auto,
+
+		/**
+		 * Whether to use strict matching on attributes and styles.
+		 *
+		 * When true this will perform AND matching requiring all tag
+		 * attributes and styles to match.
+		 *
+		 * When false will perform OR matching and will match if any of
+		 * a tags attributes or styles match.
+		 *
+		 * @type {Boolean}
+		 * @since 3.1.0
+		 */
+		strictMatch: false
+	};
+
+	/**
+	 * Converts a number 0-255 to hex.
+	 *
+	 * Will return 00 if number is not a valid number.
+	 *
+	 * @param  {any} number
+	 * @return {string}
+	 * @private
+	 */
+	function toHex(number) {
+		number = parseInt(number, 10);
+
+		if (isNaN(number)) {
+			return '00';
+		}
+
+		number = Math.max(0, Math.min(number, 255)).toString(16);
+
+		return number.length < 2 ? '0' + number : number;
+	}
+
+	/**
+	 * Normalises a CSS colour to hex #xxxxxx format
+	 *
+	 * @param  {string} colorStr
+	 * @return {string}
+	 * @private
+	 */
+	function _normaliseColour(colorStr) {
+		var match;
+
+		colorStr = colorStr || '#000';
+
+		// rgb(n,n,n);
+		if ((match =
+			colorStr.match(/rgb\((\d{1,3}),\s*?(\d{1,3}),\s*?(\d{1,3})\)/i))) {
+			return '#' +
+				toHex(match[1]) +
+				toHex(match[2]) +
+				toHex(match[3]);
+		}
+
+		// expand shorthand
+		if ((match = colorStr.match(/#([0-9a-f])([0-9a-f])([0-9a-f])\s*?$/i))) {
+			return '#' +
+				match[1] + match[1] +
+				match[2] + match[2] +
+				match[3] + match[3];
+		}
+
+		return colorStr;
+	}
+
+	/**
+	 * SCEditor BBCode format
+	 * @since 2.0.0
+	 */
+	function bbcodeFormat() {
+		var base = this;
+
+		base.stripQuotes = _stripQuotes;
+
+		/**
+		 * cache of all the tags pointing to their bbcodes to enable
+		 * faster lookup of which bbcode a tag should have
+		 * @private
+		 */
+		var tagsToBBCodes = {};
+
+		/**
+		 * Allowed children of specific HTML tags. Empty array if no
+		 * children other than text nodes are allowed
+		 * @private
+		 */
+		var validChildren = {
+			ul: ['li', 'ol', 'ul'],
+			ol: ['li', 'ol', 'ul'],
+			table: ['tr'],
+			tr: ['td', 'th'],
+			code: ['br', 'p', 'div']
+		};
+
+		/**
+		 * Populates tagsToBBCodes and stylesToBBCodes for easier lookups
+		 *
+		 * @private
+		 */
+		function buildBbcodeCache() {
+			each(bbcodeHandlers, function (bbcode, handler) {
+				var
+					isBlock = handler.isInline === false,
+					tags   = bbcodeHandlers[bbcode].tags,
+					styles = bbcodeHandlers[bbcode].styles;
+
+				if (styles) {
+					tagsToBBCodes['*'] = tagsToBBCodes['*'] || {};
+					tagsToBBCodes['*'][isBlock] =
+						tagsToBBCodes['*'][isBlock] || {};
+					tagsToBBCodes['*'][isBlock][bbcode] = [
+						['style', Object.entries(styles)]
+					];
+				}
+
+				if (tags) {
+					each(tags, function (tag, values) {
+						if (values && values.style) {
+							values.style = Object.entries(values.style);
+						}
+
+						tagsToBBCodes[tag] = tagsToBBCodes[tag] || {};
+						tagsToBBCodes[tag][isBlock] =
+							tagsToBBCodes[tag][isBlock] || {};
+						tagsToBBCodes[tag][isBlock][bbcode] =
+							values && Object.entries(values);
+					});
+				}
+			});
+		};
+
+		/**
+		 * Handles adding newlines after block level elements
+		 *
+		 * @param {HTMLElement} element The element to convert
+		 * @param {string} content  The tags text content
+		 * @return {string}
+		 * @private
+		 */
+		function handleBlockNewlines(element, content) {
+			var	tag = element.nodeName.toLowerCase();
+			var isInline = dom.isInline;
+			if (!isInline(element, true) || tag === 'br') {
+				var	isLastBlockChild, parent, parentLastChild,
+					previousSibling = element.previousSibling;
+
+				// Skips selection makers and ignored elements
+				// Skip empty inline elements
+				while (previousSibling &&
+						previousSibling.nodeType === 1 &&
+						!is(previousSibling, 'br') &&
+						isInline(previousSibling, true) &&
+						!previousSibling.firstChild) {
+					previousSibling = previousSibling.previousSibling;
+				}
+
+				// If it's the last block of an inline that is the last
+				// child of a block then it shouldn't cause a line break
+				// <block><inline><br></inline></block>
+				do {
+					parent          = element.parentNode;
+					parentLastChild = parent && parent.lastChild;
+
+					isLastBlockChild = parentLastChild === element;
+					element = parent;
+				} while (parent && isLastBlockChild && isInline(parent, true));
+
+				// If this block is:
+				//	* Not the last child of a block level element
+				//	* Is a <li> tag (lists are blocks)
+				if (!isLastBlockChild || tag === 'li') {
+					content += '\n';
+				}
+
+				// Check for:
+				// <block>text<block>text</block></block>
+				//
+				// The second opening <block> opening tag should cause a
+				// line break because the previous sibing is inline.
+				if (tag !== 'br' && previousSibling &&
+					!is(previousSibling, 'br') &&
+					isInline(previousSibling, true)) {
+					content = '\n' + content;
+				}
+			}
+
+			return content;
+		}
+
+		/**
+		 * Handles a HTML tag and finds any matching BBCodes
+		 *
+		 * @param {HTMLElement} element The element to convert
+		 * @param {string} content  The Tags text content
+		 * @param {boolean} blockLevel
+		 * @return {string} Content with any matching BBCode tags
+		 *                  wrapped around it.
+		 * @private
+		 */
+		function handleTags(element, content, blockLevel) {
+			function isStyleMatch(style) {
+				var property = style[0];
+				var values = style[1];
+				var val = dom.getStyle(element, property);
+				var parent = element.parentNode;
+
+				// if the parent has the same style use that instead of this one
+				// so you don't end up with [i]parent[i]child[/i][/i]
+				if (!val || parent && dom.hasStyle(parent, property, val)) {
+					return false;
+				}
+
+				return !values || values.includes(val);
+			}
+
+			function createAttributeMatch(isStrict) {
+				return function (attribute) {
+					var name = attribute[0];
+					var value = attribute[1];
+
+					// code tags should skip most styles
+					if (name === 'style' && element.nodeName === 'CODE') {
+						return false;
+					}
+
+					if (name === 'style' && value) {
+						return value[isStrict ? 'every' : 'some'](isStyleMatch);
+					} else {
+						var val = attr(element, name);
+
+						return val && (!value || value.includes(val));
+					}
+				};
+			}
+
+			function handleTag(tag) {
+				if (!tagsToBBCodes[tag] || !tagsToBBCodes[tag][blockLevel]) {
+					return;
+				}
+
+				// loop all bbcodes for this tag
+				each(tagsToBBCodes[tag][blockLevel], function (bbcode, attrs) {
+					var fn, format,
+						isStrict = bbcodeHandlers[bbcode].strictMatch;
+
+					if (typeof isStrict === 'undefined') {
+						isStrict = base.opts.strictMatch;
+					}
+
+					// Skip if the element doesn't have the attribute or the
+					// attribute doesn't match one of the required values
+					fn = isStrict ? 'every' : 'some';
+					if (attrs && !attrs[fn](createAttributeMatch(isStrict))) {
+						return;
+					}
+
+					format = bbcodeHandlers[bbcode].format;
+					if (isFunction(format)) {
+						content = format.call(base, element, content);
+					} else {
+						content = _formatString(format, content);
+					}
+					return false;
+				});
+			}
+
+			handleTag('*');
+			handleTag(element.nodeName.toLowerCase());
+			return content;
+		}
+
+		/**
+		 * Converts a HTML dom element to BBCode starting from
+		 * the innermost element and working backwards
+		 *
+		 * @private
+		 * @param {HTMLElement}	element
+		 * @param {boolean}	hasCodeParent
+		 * @return {string} BBCode
+		 * @memberOf SCEditor.plugins.bbcode.prototype
+		 */
+		function elementToBbcode(element, hasCodeParent) {
+			var toBBCode = function (node, hasCodeParent, vChildren) {
+				var ret = '';
+
+				dom.traverse(node, function (node) {
+					var	content      = '',
+						nodeType     = node.nodeType,
+						tag          = node.nodeName.toLowerCase(),
+						isCodeTag    = tag === 'code',
+						isEmoticon   = tag === 'img' &&
+							!!attr(node, EMOTICON_DATA_ATTR),
+						vChild       = validChildren[tag],
+						firstChild   = node.firstChild,
+						isValidChild = true;
+
+					if (vChildren) {
+						isValidChild = vChildren.indexOf(tag) > -1;
+
+						// Emoticons should always be converted
+						if (isEmoticon) {
+							isValidChild = true;
+						}
+
+						// if this tag is one of the parents allowed children
+						// then set this tags allowed children to whatever it
+						// allows, otherwise set to what the parent allows
+						if (!isValidChild) {
+							vChild = vChildren;
+						}
+					}
+
+					// 1 = element
+					if (nodeType === 1) {
+						// skip empty nlf elements (new lines automatically
+						// added after block level elements like quotes)
+						if (is(node, '.sceditor-nlf') && !firstChild) {
+							return;
+						}
+
+						// don't convert iframe contents
+						if (tag !== 'iframe') {
+							content = toBBCode(node, hasCodeParent || isCodeTag,
+								vChild);
+						}
+
+						// TODO: isValidChild is no longer needed. Should use
+						// valid children bbcodes instead by creating BBCode
+						// tokens like the parser.
+						if (isValidChild) {
+							// Emoticons should be converted if they have found
+							// their way into a code tag
+							if (!hasCodeParent || isEmoticon) {
+								if (!isCodeTag) {
+									// Parse inline codes first so they don't
+									// contain block level codes
+									content = handleTags(node, content, false);
+								}
+
+								content = handleTags(node, content, true);
+							}
+							ret += handleBlockNewlines(node, content);
+						} else {
+							ret += content;
+						}
+					// 3 = text
+					} else if (nodeType === 3) {
+						ret += node.nodeValue;
+					}
+				}, false, true);
+
+				return ret;
+			};
+
+			return toBBCode(element, hasCodeParent);
+		};
+
+		/**
+		 * Initializer
+		 * @private
+		 */
+		base.init = function () {
+			base.opts = this.opts;
+			base.elementToBbcode = elementToBbcode;
+
+			// build the BBCode cache
+			buildBbcodeCache();
+
+			this.commands = extend(
+				true, {}, defaultCommandsOverrides, this.commands
+			);
+
+			// Add BBCode helper methods
+			this.toBBCode   = base.toSource;
+			this.fromBBCode = base.toHtml;
+		};
+
+		/**
+		 * Converts BBCode into HTML
+		 *
+		 * @param {boolean} asFragment
+		 * @param {string} source
+		 * @param {boolean} [legacyAsFragment] Used by fromBBCode() method
+		 */
+		function toHtml(asFragment, source, legacyAsFragment) {
+			var	parser = new BBCodeParser(base.opts.parserOptions);
+			var toHTML = (asFragment || legacyAsFragment) ?
+				parser.toHTMLFragment :
+				parser.toHTML;
+
+			return toHTML(base.opts.bbcodeTrim ? source.trim() : source);
+		}
+
+		/**
+		 * Converts HTML into BBCode
+		 *
+		 * @param {boolean} asFragment
+		 * @param {string}	html
+		 * @param {!Document} [context]
+		 * @param {!HTMLElement} [parent]
+		 * @return {string}
+		 * @private
+		 */
+		function toSource(asFragment, html, context, parent) {
+			context = context || document;
+
+			var	bbcode, elements;
+			var hasCodeParent = !!dom.closest(parent, 'code');
+			var containerParent = context.createElement('div');
+			var container = context.createElement('div');
+			var parser = new BBCodeParser(base.opts.parserOptions);
+
+			container.innerHTML = html;
+			css(containerParent, 'visibility', 'hidden');
+			containerParent.appendChild(container);
+			context.body.appendChild(containerParent);
+
+			if (asFragment) {
+				// Add text before and after so removeWhiteSpace doesn't remove
+				// leading and trailing whitespace
+				containerParent.insertBefore(
+					context.createTextNode('#'),
+					containerParent.firstChild
+				);
+				containerParent.appendChild(context.createTextNode('#'));
+			}
+
+			// Match parents white-space handling
+			if (parent) {
+				css(container, 'whiteSpace', css(parent, 'whiteSpace'));
+			}
+
+			// Remove all nodes with sceditor-ignore class
+			elements = container.getElementsByClassName('sceditor-ignore');
+			while (elements.length) {
+				elements[0].parentNode.removeChild(elements[0]);
+			}
+
+			dom.removeWhiteSpace(containerParent);
+
+			bbcode = elementToBbcode(container, hasCodeParent);
+
+			context.body.removeChild(containerParent);
+
+			bbcode = parser.toBBCode(bbcode, true);
+
+			if (base.opts.bbcodeTrim) {
+				bbcode = bbcode.trim();
+			}
+
+			return bbcode;
+		};
+
+		base.toHtml = toHtml.bind(null, false);
+		base.fragmentToHtml = toHtml.bind(null, true);
+		base.toSource = toSource.bind(null, false);
+		base.fragmentToSource = toSource.bind(null, true);
+	};
+
+	/**
+	 * Gets a BBCode
+	 *
+	 * @param {string} name
+	 * @return {Object|null}
+	 * @since 2.0.0
+	 */
+	bbcodeFormat.get = function (name) {
+		return bbcodeHandlers[name] || null;
+	};
+
+	/**
+	 * Adds a BBCode to the parser or updates an existing
+	 * BBCode if a BBCode with the specified name already exists.
+	 *
+	 * @param {string} name
+	 * @param {Object} bbcode
+	 * @return {this}
+	 * @since 2.0.0
+	 */
+	bbcodeFormat.set = function (name, bbcode) {
+		if (name && bbcode) {
+			// merge any existing command properties
+			bbcode = extend(bbcodeHandlers[name] || {}, bbcode);
+
+			bbcode.remove = function () {
+				delete bbcodeHandlers[name];
+			};
+
+			bbcodeHandlers[name] = bbcode;
+		}
+
+		return this;
+	};
+
+	/**
+	 * Renames a BBCode
+	 *
+	 * This does not change the format or HTML handling, those must be
+	 * changed manually.
+	 *
+	 * @param  {string} name    [description]
+	 * @param  {string} newName [description]
+	 * @return {this|false}
+	 * @since 2.0.0
+	 */
+	bbcodeFormat.rename = function (name, newName) {
+		if (name in bbcodeHandlers) {
+			bbcodeHandlers[newName] = bbcodeHandlers[name];
+
+			delete bbcodeHandlers[name];
+		}
+
+		return this;
+	};
+
+	/**
+	 * Removes a BBCode
+	 *
+	 * @param {string} name
+	 * @return {this}
+	 * @since 2.0.0
+	 */
+	bbcodeFormat.remove = function (name) {
+		if (name in bbcodeHandlers) {
+			delete bbcodeHandlers[name];
+		}
+
+		return this;
+	};
+
+	bbcodeFormat.formatBBCodeString = formatBBCodeString;
+
+	sceditor.formats.bbcode = bbcodeFormat;
+	sceditor.BBCodeParser = BBCodeParser;
+}(sceditor));

+ 112 - 0
public/js/sc/icons/monocons.js

@@ -0,0 +1,112 @@
+/**
+ * SCEditor SVG monocons plugin
+ * http://www.sceditor.com/
+ *
+ * Copyright (C) 2017, Sam Clarke (samclarke.com)
+ *
+ * SCEditor is licensed under the MIT license:
+ *	http://www.opensource.org/licenses/mit-license.php
+ *
+ * @author Sam Clarke
+ */
+(function (document, sceditor) {
+	'use strict';
+
+	var dom = sceditor.dom;
+
+	/* eslint max-len: off*/
+	var icons = {
+		'bold': '<text x="50%" y="50%" text-anchor="middle" dy=".5ex" font-family="Dejavu Sans, Helvetica, Arial, sans-serif" font-size="15" font-weight="bold">B</text>',
+		'bulletlist': '<path d="M6 2h9v2H6zm0 5h9v2H6zm0 5h9v2H6z"/><circle cx="3" cy="3" r="1.75"/><circle cx="3" cy="8" r="1.75"/><circle cx="3" cy="13" r="1.75"/>',
+		'center': '<path d="M1 1h14v2H1zm2 4h10v2H3zM1 9h14v2H1zm2 4h10v2H3z"/>',
+		'code': '<path d="M7 6L4 9l3 3v-1.5L5.5 9 7 7.5zm2 0v1.5L10.5 9 9 10.5V12l3-3zM2.406 1A.517.517 0 0 0 2 1.5v13c0 .262.238.5.5.5h11a.52.52 0 0 0 .5-.5V4.375c.002-.102-.13-.193-.156-.219l-3-3A.506.506 0 0 0 10.5 1zM3 2h7v2.5c0 .262.238.5.5.5H13v9H3zm8 .688L12.313 4H11z"/>',
+		'color': '<text x="50%" y="8" text-anchor="middle" dy=".5ex" font-family="Dejavu Sans, Helvetica, Arial, sans-serif" font-size="13" font-weight="bold">A</text><path class="sce-color" d="M2 13h12v2H2z"/>',
+		'copy': '<path d="M6.404 5.002a.5.5 0 0 0-.406.5v10a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5V8.596a.492.492 0 0 0 0-.094.662.662 0 0 0 0-.063v-.063l-.031-.063v-.031a.557.557 0 0 0-.094-.094l-.031-.031-2.875-2.844a.498.498 0 0 0-.125-.156.5.5 0 0 0-.344-.156h-5a.59.59 0 0 0-.094.001c-.239.046.031-.003 0 0zm.594 1h4v2.5a.5.5 0 0 0 .5.5h2.5v6h-7v-9zm5 .687l1.313 1.313h-1.313V6.689zM1.406.002a.517.517 0 0 0-.406.5v10c0 .262.238.5.5.5H7V6l3-.063V3.596a.492.492 0 0 0 0-.094.331.331 0 0 0 0-.063v-.063c-.009-.021-.02-.041-.031-.062v-.031a.597.597 0 0 0-.094-.094l-.031-.031L6.969.314a.484.484 0 0 0-.125-.156A.506.506 0 0 0 6.5.002h-5a.492.492 0 0 0-.094 0c-.229.044.032-.003 0 0zm.594 1h4v2.5c0 .262.238.5.5.5H9v1.029L7 5 6 6v4l-4 .002v-9zm5 .687l1.313 1.313H7V1.689z"/>',
+		'cut': '<path d="M3 .5c0 2.936 3.774 7.73 3.938 7.938l-1.813 2.844A2.46 2.46 0 0 0 4 11c-1.375 0-2.5 1.125-2.5 2.5S2.625 16 4 16s2.5-1.125 2.5-2.5c0-.444-.138-.856-.344-1.22L8 9.845l1.844 2.438A2.473 2.473 0 0 0 9.5 13.5c0 1.375 1.125 2.5 2.5 2.5s2.5-1.125 2.5-2.5S13.375 11 12 11a2.46 2.46 0 0 0-1.125.28L9.062 8.439C9.226 8.232 13 3.437 13 .5h-1L8 6.78 4 .5H3zM4 12c.834 0 1.5.666 1.5 1.5S4.834 15 4 15s-1.5-.666-1.5-1.5S3.166 12 4 12zm8 0c.834 0 1.5.666 1.5 1.5S12.834 15 12 15s-1.5-.666-1.5-1.5.666-1.5 1.5-1.5z"/>',
+		'date': '<path d="M8.1 7v1h2.7v1H8.094v3H11.7v-1H9v-1h2.7V7zM4.5 7v1h.8v3h-.8v1h2.7v-1h-.9V7zM.9 1v14h14.4V1h-1.8v2h-2.7V1H5.4v2H2.7V1zm.9 4h12.6v9H1.8z"/>',
+		'email': '<path d="M1 4.5v8c0 .262.238.5.5.5h13a.52.52 0 0 0 .5-.5V4.594C15 4 15 4 14.5 4H1.563C1 4 1 4 1 4.5zM2 5h12v7H2V5zm-.187-.906l-.625.812 6.5 5 .312.219.313-.219 6.5-5-.625-.813L8 8.844l-6.187-4.75z"/>',
+		'emoticon': '<path d="M8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1zm0 1a6 6 0 1 1 0 12A6 6 0 0 1 8 2zM6 5c-.546 0-1 .454-1 1s.454 1 1 1 1-.454 1-1-.454-1-1-1zm4 0c-.547 0-1 .454-1 1s.453 1 1 1c.547 0 1-.454 1-1s-.453-1-1-1zM4.5 9.5s-.002.652.469 1.281C5.44 11.409 6.389 12 8 12c1.611 0 2.561-.591 3.031-1.219.47-.629.469-1.281.469-1.281h-1s-.002.314-.281.688c-.279.374-.83.813-2.219.813-1.389 0-1.94-.44-2.219-.813C5.502 9.814 5.5 9.5 5.5 9.5z"/>',
+		'font': '<path d="M7.953 9.75h-4.06l-.395 1.141c-.132.381-.254.752-.368 1.109H.7c.391-1.119.762-2.154 1.113-3.105a104.642 104.642 0 0 1 2.024-5.079 52.23 52.23 0 0 1 1.016-2.212h2.218a80.63 80.63 0 0 1 2.011 4.605c.337.84.105.338.458 1.288s-1.455 2.63-1.587 2.253zM5.912 3.959c-.052.151-.129.357-.229.616-.1.26-.215.56-.343.901-.129.341-.273.716-.431 1.125-.159.409-.32.839-.484 1.288h2.972c-.159-.45-.312-.882-.461-1.292a46.81 46.81 0 0 0-.425-1.127c-.135-.34-.252-.641-.354-.9-.1-.26-.182-.463-.245-.611zm6.949 10.042a36.325 36.325 0 0 0-.35-1.037l-.371-1.063H8.352l-.368 1.064A41.69 41.69 0 0 0 7.64 14H5.373c.365-1.045.711-2.01 1.039-2.896.328-.886.648-1.723.962-2.506.313-.786.623-1.53.927-2.235.305-.705.62-1.393.948-2.065h2.069c.318.672.634 1.36.941 2.065.311.705.621 1.449.936 2.235.314.783.636 1.619.964 2.506.327.888.676 1.853 1.041 2.896l-2.339.001zm-2.625-7.504c-.049.141-.118.333-.213.576-.094.242-.2.521-.319.84-.121.317-.254.668-.402 1.051-.147.382-.299.783-.45 1.201h2.772c-.147-.42-.291-.822-.433-1.205a43.073 43.073 0 0 0-.396-1.053c-.125-.317-.233-.598-.33-.84a13.884 13.884 0 0 0-.229-.57z"/>',
+		'format': '<path d="M10.5 2v1.5H12c.235 0 .401-.009.5 0 .008.088 0 .279 0 .5v2H14V3.437c0-.237-.01-.409-.031-.593-.022-.185-.067-.42-.25-.594s-.407-.2-.594-.219A5.693 5.693 0 0 0 12.5 2zm0-2L7.187 2.5 10.5 5zm.5 5.187L13.5 8.5 16 5.187zm-.958-.339h-2.03l-3.234 8.456c-.154.392-.336.994-.854 1.022v.518h2.744v-.518c-.644-.168-.658-.462-.434-1.036l.784-2.086h3.43l.854 2.086c.238.574.308.924-.406 1.036v.518h3.276v-.518c-.434-.056-.546-.364-.686-.728l-3.444-8.75M7.424 10l1.26-3.318L10 10H7.424M4.912.975h-1.63L.686 7.764c-.124.314-.27.798-.686.82V9h2.203v-.416c-.517-.135-.528-.37-.348-.832l.629-1.674h2.754l.685 1.674c.192.461.248.742-.325.832V9c1.73.137 1.837-.002 2.079-1L4.912.975M2.81 5.11l1.012-2.664L4.878 5.11H2.81"/>',
+		'grip': '<path d="M14.656 5.156l-10 10 .688.688 10-10-.688-.688zm0 3l-7 7 .688.688 7-7-.688-.688zm0 3l-4 4 .688.688 4-4-.688-.688z"/>',
+		'horizontalrule': '<path d="M2 2v1h12V2H2zm0 2v1h9V4H2zm0 2v1h12V6H2zm0 2v2h12V8H2z"/>',
+		'image': '<path d="M.5 2.5v11h15v-11H.5zm1 1h13v9h-13v-9z"/><circle cx="4" cy="6" r="1.25"/><path d="M1 11h14v2H1z"/><path d="M5 12l2-4 2 4z"/><path d="M7 12l4-7 4 7z"/>',
+		'indent': '<path d="M1 1h14v2H1zm5 4h9v2H6zm0 4h9v2H6zm-5 4h14v2H1zm4-5L1 5v6z"/>',
+		'italic': '<text x="50%" y="50%" text-anchor="middle" dy=".5ex" font-family="Dejavu Sans, Helvetica, Arial, sans-serif" font-weight="bold" font-size="15" font-style="italic">i</text>',
+		'justify': '<path d="M1 1h14v2H1zm0 4h14v2H1zm0 4h14v2H1zm0 4h14v2H1z"/>',
+		'left': '<path d="M1 1h14v2H1zm0 4h10v2H1zm0 4h14v2H1zm0 4h10v2H1z"/>',
+		'link': '<path d="M2 4c-.625 0-1.009.438-1.188.75s-.269.63-.344.969c-.15.677-.219 1.476-.219 2.28s.068 1.605.219 2.282c.075.339.165.625.344.938s.563.78 1.188.78h4v-2H2.469c-.022-.065-.042-.06-.063-.155-.1-.447-.156-1.15-.156-1.844s.057-1.396.156-1.844c.02-.088.042-.092.063-.156H6V4H2zm8 0v2h3.531c.021.064.043.068.063.156.1.448.156 1.149.156 1.844s-.057 1.396-.156 1.844c-.021.096-.041.09-.063.156H10v2h4c.625 0 1.009-.47 1.188-.781s.269-.6.344-.938c.15-.678.219-1.476.219-2.281s-.068-1.604-.219-2.281c-.075-.34-.165-.656-.344-.97S14.625 4 14 4h-4zM5.719 7c-.523.074-.949.602-.875 1.125S5.477 9.074 6 9h4c.528.01 1-.472 1-1s-.472-1.007-1-1H6a.593.593 0 0 0-.188 0h-.093z"/>',
+		'ltr': '<path d="M10.313 1.937c-.98 0-1.752.284-2.344.813-.592.529-.906 1.228-.906 2.094 0 .811.275 1.467.781 1.969.506.497 1.227.792 2.156.906V14h2V3h1v11h1V1.939zM2 4v8l4-4z"/>',
+		'maximize': '<path d="M2 7l1.75-1.75-2-2L0 5V0h5L3.25 1.75l2 2L7 2v5H2zm9 9l1.75-1.75-2-2L9 14V9h5l-1.75 1.75 2 2L16 11v5h-5zm-6 0l-1.75-1.75 2-2L7 14V9H2l1.75 1.75-2 2L0 11v5h5zm6-16l1.75 1.75-2 2L9 2v5h5l-1.75-1.75 2-2L16 5V0h-5z"/>',
+		'orderedlist': '<path d="M6 2h9v2H6zm0 5h9v2H6zm0 5h9v2H6zm-2.799.846q.392.1.594.352.205.25.205.636 0 .576-.441.877-.441.298-1.287.298-.298 0-.599-.05-.298-.046-.591-.142v-.77q.28.14.555.212.277.07.545.07.396 0 .607-.137.212-.138.212-.394 0-.265-.218-.4-.215-.137-.638-.137h-.4v-.644h.421q.376 0 .56-.116.185-.12.185-.36 0-.224-.18-.346-.178-.122-.505-.122-.242 0-.488.055-.246.054-.49.16v-.731q.295-.083.586-.125.29-.041.57-.041.756 0 1.13.249.375.246.375.744 0 .34-.179.558-.179.215-.529.304zm-.905-3.609H4v.734H1.186v-.734L2.599 7.99q.19-.172.28-.335.091-.163.091-.34 0-.272-.184-.438-.182-.166-.485-.166-.234 0-.511.101-.278.099-.594.296v-.851q.337-.112.667-.169.329-.06.645-.06.696 0 1.08.307.386.306.386.853 0 .317-.163.592-.164.272-.688.731l-.827.726zM1.228 4.276h.903V1.714l-.927.19V1.21l.922-.191h.971v3.258H4v.706H1.228v-.706z"/>',
+		'outdent': '<path d="M1 1h14v2H1zm0 4h9v2H1zm0 4h9v2H1zm0 4h14v2H1zm10-5l4-3v6z"/>',
+		'paste': '<path d="M4.406 0A.5.5 0 0 0 4 .5V1H1.5a.5.5 0 0 0-.5.5v10a.5.5 0 0 0 .5.5H6v2.5a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5V7.594a.492.492 0 0 0 0-.094.436.436 0 0 0 0-.125.916.916 0 0 0-.031-.063v-.031a.749.749 0 0 0-.063-.063.749.749 0 0 0-.063-.063l-2.875-2.844a.498.498 0 0 0-.125-.156A.498.498 0 0 0 11.5 4H10V1.5a.5.5 0 0 0-.5-.5H7V.5a.5.5 0 0 0-.5-.5h-2a.492.492 0 0 0-.094 0c-.239.045.032-.003 0 0zM2 2h1v.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5V2h1v2H6.5a.64.64 0 0 0-.062 0 .493.493 0 0 0-.094.031.474.474 0 0 0-.125.063l-.031.031-.031.031a.916.916 0 0 0-.063.031.47.47 0 0 0-.031.094l-.031.031A.506.506 0 0 0 6 4.5V11H2V2zm5 3h4v2.5a.5.5 0 0 0 .5.5H14v6H7v-2.406a.492.492 0 0 0 0-.094V5zm5 .688L13.313 7H12V5.688zM4.406 0A.5.5 0 0 0 4 .5V1H1.5a.5.5 0 0 0-.5.5v10a.5.5 0 0 0 .5.5h5a.5.5 0 0 0 .5-.5V5h2.5a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5H7V.5a.5.5 0 0 0-.5-.5h-2a.492.492 0 0 0-.094 0c-.239.045.032-.003 0 0zM2 2h1v.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5V2h1v2H6.5a.5.5 0 0 0-.5.5V11H2V2zm4.406 2A.5.5 0 0 0 6 4.5v10a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5V7.594a.492.492 0 0 0 0-.094.331.331 0 0 0 0-.063v-.063a.916.916 0 0 0-.031-.063V7.28a.523.523 0 0 0-.094-.094l-.031-.031-2.875-2.844a.498.498 0 0 0-.125-.156A.503.503 0 0 0 11.5 4h-5a.492.492 0 0 0-.094 0c-.239.045.032-.003 0 0zM7 5h4v2.5a.5.5 0 0 0 .5.5H14v6H7V5zm5 .688L13.313 7H12V5.688zM8 12h5v1H8v-1zm0-2h5v1H8v-1zm0-2h5v1H8V8zm0-2h3v1H8V6z"/>',
+		'pastetext': '<path d="M4.406 0A.5.5 0 0 0 4 .5V1H1.5a.5.5 0 0 0-.5.5v10a.5.5 0 0 0 .5.5H6v2.5a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5V7.594a.492.492 0 0 0 0-.094.436.436 0 0 0 0-.125.916.916 0 0 0-.031-.063v-.031a.749.749 0 0 0-.063-.063.749.749 0 0 0-.063-.063l-2.875-2.844a.498.498 0 0 0-.125-.156A.498.498 0 0 0 11.5 4H10V1.5a.5.5 0 0 0-.5-.5H7V.5a.5.5 0 0 0-.5-.5h-2a.492.492 0 0 0-.094 0zM2 2h1v.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5V2h1v2H6.5a.64.64 0 0 0-.062 0 .493.493 0 0 0-.094.031.474.474 0 0 0-.125.063l-.031.031-.031.031a.916.916 0 0 0-.063.031.47.47 0 0 0-.031.094l-.031.031A.506.506 0 0 0 6 4.5V11H2V2zm5 3h4v2.5a.5.5 0 0 0 .5.5H14v6H7v-2.406a.492.492 0 0 0 0-.094V5zm5 .688L13.313 7H12V5.688zM4.406 0A.5.5 0 0 0 4 .5V1H1.5a.5.5 0 0 0-.5.5v10a.5.5 0 0 0 .5.5h5a.5.5 0 0 0 .5-.5V5h2.5a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5H7V.5a.5.5 0 0 0-.5-.5h-2a.492.492 0 0 0-.094 0zM2 2h1v.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5V2h1v2H6.5a.5.5 0 0 0-.5.5V11H2V2zm4.406 2A.5.5 0 0 0 6 4.5v10a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5V7.594a.492.492 0 0 0 0-.094.331.331 0 0 0 0-.063v-.062a.916.916 0 0 0-.031-.063v-.031a.523.523 0 0 0-.094-.094l-.031-.031-2.875-2.844a.498.498 0 0 0-.125-.156A.5.5 0 0 0 11.5 4h-5a.492.492 0 0 0-.094 0zM7 5h4v2.5a.5.5 0 0 0 .5.5H14v6H7V5zm5 .688L13.313 7H12V5.688z"/>',
+		'print': '<path d="M4 1v3H1v8h2V6h10v6h2V4h-3V1zm1 1h6v2H5zM4 7v8h8V7zm1 1h6v6H5zm1 1v1h4V9zm0 2v1h4v-1z"/>',
+		'quote': '<path d="M8 2.013c-1.998 0-3.818.382-5.188 1.125S.499 5.054.499 6.513c0 1.237.926 2.345 2.281 3.156s3.197 1.344 5.219 1.344c.344 0 .563.019.906 0l5.875 2.938c.377.18.854-.32.656-.688l-1.813-3.656c1.242-.79 1.875-2.014 1.875-3.094 0-1.46-.943-2.632-2.313-3.375S9.998 2.013 8 2.013z"/>',
+		'redo': '<path d="M9 7l5-5v5z"/><path d="M9.553 2.205c1 .268 1.932.796 2.69 1.553l.706.707-1.414 1.414-.707-.707a3.995 3.995 0 0 0-3.863-1.035 3.995 3.995 0 0 0-2.828 2.828 3.995 3.995 0 0 0 1.035 3.863l.707.707-1.414 1.414-.707-.707a6.003 6.003 0 0 1-1.553-5.795 6.003 6.003 0 0 1 7.348-4.242z"/>',
+		'removeformat': '<path d="M8.781 2l-.125.125L3.781 7l-.125.125-3 3-.313.313.25.344 3 4 .156.219h2.47l.125-.156 3-3 .313-.313 4.688-4.688.313-.313-.25-.344-3-4-.156-.188H8.781zm.407 1h.594l-4 4h-.594l4-4zm1.75.25l2.406 3.188-4.281 4.28-2.406-3.187 4.281-4.281z"/>',
+		'right': '<path d="M1 1h14v2H1zm4 4h10v2H5zM1 9h14v2H1zm4 4h10v2H5z"/>',
+		'rtl': '<path d="M5.344 2.001c-.98 0-1.783.284-2.375.813-.592.529-.875 1.227-.875 2.093 0 .811.244 1.467.75 1.969.506.497 1.227.792 2.156.906V14h2V3.001L8 3v11h1V2zM14 4l-4 4 4 4z"/>',
+		'size': '<path d="M12.5.656L10 4h5L12.5.656zM4.594 4.5a49.476 49.476 0 0 0-.875 1.906c-.277.65-.581 1.334-.875 2.063-.286.729-.572 1.52-.875 2.344S1.338 12.53 1 13.5h2.094c.095-.313.2-.64.313-.97.121-.328.262-.64.375-.968h3.5c.113.329.231.64.344.969.121.329.217.656.313.969h2.188c-.338-.971-.666-1.864-.969-2.688s-.611-1.615-.906-2.344a56.045 56.045 0 0 0-.844-2.063c-.286-.66-.581-1.282-.875-1.906H4.594zM10 6l2.5 3.313L15 6h-5zm-4.5.53c.052.13.132.307.219.532.086.225.2.486.313.78.121.296.245.614.375.97s.268.734.406 1.125H4.25c.139-.391.245-.77.375-1.125.139-.355.293-.674.406-.97s.194-.555.281-.78c.087-.224.145-.401.188-.531z"/>',
+		'source': '<path d="M4.937 3.939L1 8.499l3.937 4.564L6 12 3 8.499 6 5zm6.126 0L10 5.002l3 3.503-3 3.497 1.063 1.063L15 8.505z"/>',
+		'strike': '<text x="50%" y="50%" text-anchor="middle" dy=".5ex" font-family="Dejavu Sans, Helvetica, Arial, sans-serif" font-size="15" font-weight="bold">S</text><path d="M1 7v1h14V7H1z"/>',
+		'subscript': '<path d="M11 10v1h3v1h-3v3h4v-1h-3v-1h3v-3zM1 3l3 5-3 5h2l3-5H4l3 5h2L6 8l3-5H7L4 8h2L3 3z"/>',
+		'superscript': '<path d="M11 1v1h3v1h-3v3h4V5h-3V4h3V1zM1 3l3 5-3 5h2l3-5H4l3 5h2L6 8l3-5H7L4 8h2L3 3z"/>',
+		'table': '<path d="M1 2h14v2H1zm0 2v10h14V4H1zm1 1h3.5v2H2V5zm4.5 0h3v2h-3V5zm4 0H14v2h-3.5V5zM2 8h3.5v2H2V8zm4.5 0h3v2h-3V8zm4 0H14v2h-3.5V8zM2 11h3.5v2H2v-2zm4.5 0h3v2h-3v-2zm4 0H14v2h-3.5v-2z"/>',
+		'time': '<path d="M8 0C3 0 0 4 0 8s3 8 8 8 8-4 8-8-3-8-8-8zm0 2c3.461 0 6 2.539 6 6s-2.539 6-6 6c-3.46 0-6-2.539-6-6s2.54-6 6-6zM7 3v6l2.5 2L11 9.5 9 8V3z"/>',
+		'underline': '<text x="50%" y="50%" text-anchor="middle" dy=".5ex" font-family="Dejavu Sans, Helvetica, Arial, sans-serif" font-weight="bold" font-size="15" text-decoration="underline">U</text>',
+		'undo': '<path d="M2 7h5L2 2z"/><path d="M6.447 2.205c-1 .268-1.932.796-2.69 1.553l-.706.707 1.414 1.414.707-.707a3.995 3.995 0 0 1 3.863-1.035 3.995 3.995 0 0 1 2.828 2.828 3.995 3.995 0 0 1-1.035 3.863l-.707.707 1.414 1.414.707-.707a6.003 6.003 0 0 0 1.553-5.795 6.003 6.003 0 0 0-7.348-4.242z"/>',
+		'unlink': '<path d="M2 4c-.625 0-1.009.438-1.188.75s-.269.63-.344.969c-.15.677-.219 1.476-.219 2.28s.068 1.605.219 2.282c.075.339.165.625.344.938s.563.78 1.188.78h4v-2H2.469c-.022-.065-.042-.06-.063-.155-.1-.447-.156-1.15-.156-1.844s.057-1.396.156-1.844c.02-.088.042-.092.063-.156H6V4H2zm8 0v2h3.531c.021.064.043.068.063.156.1.448.156 1.149.156 1.844s-.057 1.396-.156 1.844c-.021.095-.041.09-.063.156H10v2h4c.625 0 1.009-.47 1.188-.781s.269-.6.344-.938c.15-.678.219-1.476.219-2.281s-.068-1.604-.219-2.281c-.075-.34-.165-.656-.344-.97S14.625 4 14 4h-4z"/>',
+		'youtube': '<path d="M2 2C1 2 0 3 0 4v8c0 1 1 2 2 2h12c1 0 2-1 2-2V4c0-1-1-2-2-2H2zm4 3l6 3-6 3V5z"/>'
+	};
+
+	sceditor.icons.monocons = function () {
+		var nodes = {};
+		var colorPath;
+
+		return {
+			create: function (command) {
+				if (command in icons) {
+					nodes[command] = sceditor.dom.parseHTML(
+						'<svg xmlns="http://www.w3.org/2000/svg" ' +
+							'viewbox="0 0 16 16" unselectable="on">' +
+								icons[command] +
+						'</svg>'
+					).firstChild;
+
+					if (command === 'color') {
+						colorPath = nodes[command].querySelector('.sce-color');
+					}
+				}
+
+				return nodes[command];
+			},
+			update: function (isSourceMode, currentNode) {
+				if (colorPath) {
+					var color = 'inherit';
+
+					if (!isSourceMode && currentNode) {
+						color = currentNode.ownerDocument
+							.queryCommandValue('forecolor');
+					}
+
+					dom.css(colorPath, 'fill', color);
+				}
+			},
+			rtl: function (isRtl) {
+				var gripNode = nodes.grip;
+
+				if (gripNode) {
+					var transform = isRtl ? 'scaleX(-1)' : '';
+
+					dom.css(gripNode, 'transform', transform);
+					dom.css(gripNode, 'msTransform', transform);
+					dom.css(gripNode, 'webkitTransform', transform);
+				}
+			}
+		};
+	};
+
+	sceditor.icons.monocons.icons = icons;
+})(document, sceditor);

+ 68 - 0
public/js/sc/languages/ar.js

@@ -0,0 +1,68 @@
+/**
+ * @author Atramez_Zeton http://onyx-sy.net
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['ar'] = {
+		'Bold': 'عريض',
+		'Italic': 'مائل',
+		'Underline': 'خط من الأسفل',
+		'Strikethrough': 'خط في المنتصف',
+		'Subscript': 'حرف منخفض',
+		'Superscript': 'حرف مرتفع',
+		'Align left': 'انحياز إلى اليسار',
+		'Center': 'توسط',
+		'Align right': 'انحياز إالى اليمين',
+		'Justify': 'ملأ السطر',
+		'Font Name': 'نوع الخط',
+		'Font Size': 'حجم الخط',
+		'Font Color': 'لون الخط',
+		'Remove Formatting': 'ازالة التعديلات',
+		'Cut': 'قص',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Ctrl/Cmd-X متصفحك لا يدعم اوامر القص الرجاء استخدام اختصارات لوحة التحكم',
+		'Copy': 'نسخ',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Ctrl/Cmd-C متصفحك لا يدعم اوامر النسخ الرجاء استخدام اختصارات لوحة التحكم',
+		'Paste': 'لصق',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Ctrl/Cmd-V متصفحك لا يدعم اوامر اللصق الرجاء استخدام اختصارات لوحة التحكم',
+		'Paste your text inside the following box:': 'قم بلصق نصّك في المربع',
+		'Paste Text': 'الصق النص',
+		'Bullet list': 'قائمة نقطية',
+		'Numbered list': 'قائمة مرقمة',
+		'Undo': 'تراجع',
+		'Redo': 'تقدم',
+		'Rows:': 'اسطر',
+		'Cols:': 'اعمدة',
+		'Insert a table': 'ادرج جدول',
+		'Insert a horizontal rule': 'ادرج مسطرة افقية',
+		'Code': 'كود',
+		'Width (optional):': 'عرض (اختياري)',
+		'Height (optional):': 'ارتفاع (اختياري)',
+		'Insert an image': 'ادرج صورة',
+		'E-mail:': 'بريد الكتروني',
+		'Insert an email': 'ادرج بريدا الكترونيا',
+		'URL:': 'وصلة موقع',
+		'Insert a link': 'ادرج وصلة لموقع',
+		'Unlink': 'ازالة الوصلة',
+		'More': 'المزيد',
+		'Insert an emoticon': 'ادرج وجها',
+		'Video URL:': 'وصلة فيديو',
+		'Insert': 'ادرج',
+		'Insert a YouTube video': 'ادرج وصلة فيديو يوتيوب',
+		'Insert current date': 'ادرج التاريخ الحالي',
+		'Insert current time': 'ادرج الوقت الحالي',
+		'Print': 'اطبع',
+		'View source': 'اظهر المصدر',
+		'Description (optional):': 'الوصف (اختياري)',
+		'Enter the image URL:': 'ضع وصلة الصورة',
+		'Enter the e-mail address:': 'ضع عنوان البريد الإلكتروني',
+		'Enter the displayed text:': 'ضع النص الذي تريد اظهاره',
+		'Enter URL:': 'ضع وصلة موقع',
+		'Enter the YouTube video URL or ID:': 'ضع وصلة فيديو يوتيوب او رقم الفيديو',
+		'Insert a Quote': 'ادرج اقتباسا',
+		'Invalid YouTube video': 'هذا الفيديو غير صالح',
+
+		dateFormat: 'day-month-year'
+	};
+})();

+ 68 - 0
public/js/sc/languages/ca.js

@@ -0,0 +1,68 @@
+/**
+ * @author Fran Sobrino
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['ca'] = {
+		'Bold': 'Negrita',
+		'Italic': 'Cursiva',
+		'Underline': 'Subratlla',
+		'Strikethrough': 'Ratllar',
+		'Subscript': 'Sub\u00edndice',
+		'Superscript': 'Super\u00edndice',
+		'Align left': 'Alinear a l\'Esquerra',
+		'Center': 'Centrar',
+		'Align right': 'Alinear a la dreta',
+		'Justify': 'Justificar',
+		'Font Name': 'Tipus de Lletra',
+		'Font Size': 'Mida de Lletra',
+		'Font Color': 'Color de Font',
+		'Remove Formatting': 'Treure Formats',
+		'Cut': 'Tallar',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'O seu navegador non acepta o comando cortar. Por favor, empregue a combinaci\u00f3n Ctrl/Cmd-X',
+		'Copy': 'Copiar',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'O seu navegador non acepta o comando cortar. Por favor, empregue a combinaci\u00f3n Ctrl/Cmd-C',
+		'Paste': 'Pegar',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'O seu navegador non acepta o comando cortar. Por favor, empregue a combinaci\u00f3n Ctrl/Cmd-V',
+		'Paste your text inside the following box:': 'Pega o texto dentro do seguinte recadro',
+		'Paste Text': 'Pegar Texto',
+		'Bullet list': 'Llista d\'Vinyetes',
+		'Numbered list': 'Llista numerada',
+		'Undo': 'Desfer',
+		'Redo': 'Refer',
+		'Rows:': 'Files',
+		'Cols:': 'Columnes',
+		'Insert a table': 'Inserir una taula',
+		'Insert a horizontal rule': 'Insereix una Regla horitzontal',
+		'Code': 'C\u00f3digo',
+		'Width (optional):': 'Ample (Opcional)',
+		'Height (optional):': 'Alçada (Opcional)',
+		'Insert an image': 'Insereix una imatge',
+		'E-mail:': 'Correu electrònic',
+		'Insert an email': 'Insereix un Email',
+		'URL:': 'URL',
+		'Insert a link': 'Inserir un enllaç',
+		'Unlink': 'Treure un enllaç',
+		'More': 'Més',
+		'Insert an emoticon': 'Inserir un emoticon',
+		'Video URL:': 'URL del V\u00eddeo',
+		'Insert': 'Insereix',
+		'Insert a YouTube video': 'Insereix un v\u00eddeo de YouTube',
+		'Insert current date': 'Insereix data actual',
+		'Insert current time': 'Insereix hora actual',
+		'Print': 'Imprimir',
+		'View source': 'Veure C\u00f3digo',
+		'Description (optional):': 'Descripci\u00f3 (Opcional):',
+		'Enter the image URL:': 'Ingressar la URL de la imatge:',
+		'Enter the e-mail address:': 'Ingressar el correu electr\u00f3nico:',
+		'Enter the displayed text:': 'Ingressar el texto mostrat:',
+		'Enter URL:': 'Entrada URL:',
+		'Enter the YouTube video URL or ID:': 'Entrada URL ou ID de YouTube',
+		'Insert a Quote': 'v Insereix',
+		'Invalid YouTube video': 'V\u00eddeo de YouTube Inv\u00e1lido',
+
+		dateFormat: 'day-month-year'
+	};
+})();

+ 68 - 0
public/js/sc/languages/cn.js

@@ -0,0 +1,68 @@
+/**
+ * @author <Your Name> <Your e-mail/Website if you would like>
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['cn'] = {
+		'Bold': '粗体',
+		'Italic': '斜体',
+		'Underline': '下划线',
+		'Strikethrough': '删除线',
+		'Subscript': '下标',
+		'Superscript': '上标',
+		'Align left': '靠左对齐',
+		'Center': '置中',
+		'Align right': '靠右对齐',
+		'Justify': '两端对齐',
+		'Font Name': '字体',
+		'Font Size': '字号',
+		'Font Color': '字色',
+		'Remove Formatting': '格式清除',
+		'Cut': '剪切',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': '您的浏览器不支持剪切命令,请使用快捷键 Ctrl/Cmd-X',
+		'Copy': '拷贝',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': '您的浏览器不支持拷贝命令,请使用快捷键 Ctrl/Cmd-C',
+		'Paste': '粘贴',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': '您的浏览器不支持粘贴命令,请使用快捷键 Ctrl/Cmd-V',
+		'Paste your text inside the following box:': '请在下面贴入您的文本',
+		'Paste Text': '粘贴纯文本',
+		'Bullet list': '符号列表',
+		'Numbered list': '编号列表',
+		'Undo': '恢复',
+		'Redo': '撤消',
+		'Rows:': '行数',
+		'Cols:': '列数',
+		'Insert a table': '插入表格',
+		'Insert a horizontal rule': '插入分隔符',
+		'Code': '代码',
+		'Width (optional):': '宽度(选填)',
+		'Height (optional):': '高度(选填)',
+		'Insert an image': '插入图片',
+		'E-mail:': 'Email地址',
+		'Insert an email': '插入Email地址',
+		'URL:': '网址',
+		'Insert a link': '插入链接',
+		'Unlink': '取消链接',
+		'More': '更多',
+		'Insert an emoticon': '插入表情符号',
+		'Video URL:': '视频地址',
+		'Insert': '插入',
+		'Insert a YouTube video': '插入YouTube视频',
+		'Insert current date': '插入当前日期',
+		'Insert current time': '插入当前时间',
+		'Print': '打印',
+		'View source': '查看代码',
+		'Description (optional):': '描述(选填)',
+		'Enter the image URL:': '输入图片地址',
+		'Enter the e-mail address:': '输入email地址',
+		'Enter the displayed text:': '输入显示文字',
+		'Enter URL:': '输入网址',
+		'Enter the YouTube video URL or ID:': '输入YouTube地址或编号',
+		'Insert a Quote': '插入引用',
+		'Invalid YouTube video': '无效的YouTube视频',
+
+		dateFormat: 'year-month-day'
+	};
+})();

+ 71 - 0
public/js/sc/languages/cs.js

@@ -0,0 +1,71 @@
+/**
+ * @author Daniel Vítek danielvitek1@gmail.com danvitek.cz
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['cs'] = {
+		'Bold': 'Tučné',
+		'Italic': 'Kurzíva',
+		'Underline': 'Podtržené',
+		'Strikethrough': 'Přeškrtnuté',
+		'Subscript': 'Dolní index',
+		'Superscript': 'Horní index',
+		'Align left': 'Zarovnat vlevo',
+		'Center': 'Zarovnat na střed',
+		'Align right': 'Zarovnat vpravo',
+		'Justify': 'Zarovnat do bloku',
+		'Font Name': 'Výběr písma',
+		'Font Size': 'Velikost písma',
+		'Font Color': 'Barva písma',
+		'Remove Formatting': 'Vymazat formátování',
+		'Cut': 'Vyjmout',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Váš prohlížeč nepodporuje tento příkaz, použijte CTRL+X',
+		'Copy': 'Kopírovat',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Váš prohlížeč nepodporuje tento příkaz, použijte CTRL+C',
+		'Paste': 'Vložit',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Váš prohlížeč nepodporuje tento příkaz, použijte CTRL+V',
+		'Paste your text inside the following box:': 'Vložte Váš text do následujícího pole',
+		'Paste Text': 'Vložit text',
+		'Bullet list': 'Seznam',
+		'Numbered list': 'Číslovaný seznam',
+		'Undo': 'Zpět',
+		'Redo': 'Vpřed',
+		'Rows:': 'Řádků',
+		'Cols:': 'Buněk',
+		'Insert a table': 'Vložit tabulku',
+		'Insert a horizontal rule': 'Vložit vodorovnou čáru',
+		'Code': 'Vložit kód',
+		'Width (optional):': 'Šířka (volitelné)',
+		'Height (optional):': 'Výška (volitelné)',
+		'Insert an image': 'Vložit obrázek',
+		'E-mail:': 'E-mailová adresa',
+		'Insert an email': 'Vložit e-mail',
+		'URL:': 'Adresa',
+		'Insert a link': 'Vložit odkaz',
+		'Unlink': 'Zrušit odkaz',
+		'More': 'Více',
+		'Insert an emoticon': 'Vložit smajlíka',
+		'Video URL:': 'Adresa videa',
+		'Insert': 'Vložit',
+		'Insert a YouTube video': 'Vložte video z YouTube',
+		'Insert current date': 'Vložte aktuální datum',
+		'Insert current time': 'Vložte aktuální čas',
+		'Print': 'Vytisknout',
+		'View source': 'Zobrazit zdroj',
+		'Description (optional):': 'Popis (volitelné)',
+		'Enter the image URL:': 'Vložte adresu obrázku',
+		'Enter the e-mail address:': 'Vložte e-mailovou adresu',
+		'Enter the displayed text:': 'Vložte zobrazovaný text',
+		'Enter URL:': 'Vložte adresu',
+		'Enter the YouTube video URL or ID:': 'Vložte adresu YouTube videa nebo ID videa',
+		'Insert a Quote': 'Vložit citát',
+		'Invalid YouTube video': 'Neplatné YouTube video',
+		'Add indent': 'Posunout na další úroveň',
+		'Remove one indent': 'Posunout na předchozí úroveň',
+		'Maximize': 'Zobrazit přes celou obrazovku',
+
+		dateFormat: 'day-month-year'
+	};
+})();

+ 61 - 0
public/js/sc/languages/de.js

@@ -0,0 +1,61 @@
+(function () {
+	'use strict';
+
+	sceditor.locale['de'] = {
+		'Bold': 'Fett',
+		'Italic': 'Kursiv',
+		'Underline': 'Unterstrichen',
+		'Strikethrough': 'Durchgestrichen',
+		'Subscript': 'Tiefgestellt',
+		'Superscript': 'Hochgestellt',
+		'Align left': 'Linksbündig ausrichten',
+		'Center': 'Zentrieren',
+		'Align right': 'Rechtsbündig ausrichten',
+		'Justify': 'Blocksatz',
+		'Font Name': 'Schriftname',
+		'Font Size': 'Schriftgröße',
+		'Font Color': 'Schriftfarbe',
+		'Remove Formatting': 'Formatierung entfernen',
+		'Cut': 'Ausschneiden',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Ihr Browser erlaubt das Ausschneiden von Text nicht, bitte Nutzen Sie das Tastenkürzel Strg / Cmd-X',
+		'Copy': 'Kopieren',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Ihr Browser erlaubt das Kopieren von Text nicht, bitte Nutzen Sie das Tastenkürzel Strg / Cmd-C',
+		'Paste': 'Einfügen',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Ihr Browser erlaubt das Einfügen von Text nicht, bitte Nutzen Sie das Tastenkürzel Strg / Cmd-V',
+		'Paste your text inside the following box:': 'Fügen Sie Ihren Text in die folgende Box ein',
+		'Paste Text': 'Text einfügen',
+		'Bullet list': 'Aufzählungsliste',
+		'Numbered list': 'Nummerierte Liste',
+		'Add indent': 'Ebene hinzufügen',
+		'Remove one indent': 'Eine Ebene entfernen',
+		'Undo': 'Rückgängig machen',
+		'Redo': 'Wiederherstellen',
+		'Rows:': 'Zeilen',
+		'Cols:': 'Spalten',
+		'Insert a table': 'Tabelle einfügen',
+		'Insert a horizontal rule': 'Horizontale Linie einfügen',
+		'Code': 'Code',
+		'Insert a Quote': 'Zitat einfügen',
+		'Width (optional):': 'Breite (Optional)',
+		'Height (optional):': 'Höhe (Optional)',
+		'Insert an image': 'Ein Bild einfügen',
+		'E-mail:': 'E-Mail',
+		'Insert an email': 'E-Mail einfügen',
+		'URL:': 'URL',
+		'Insert a link': 'Link einfügen',
+		'Unlink': 'Link entfernen',
+		'More': 'Mehr',
+		'Left-to-Right': 'Links nach rechts',
+		'Right-to-Left': 'Rechts nach links',
+		'Insert an emoticon': 'Emoticon einfügen',
+		'Video URL:': 'Video URL',
+		'Insert': 'Einfügen',
+		'Insert a YouTube video': 'YouTube Video einfügen',
+		'Insert current date': 'Aktuelles Datum einfügen',
+		'Insert current time': 'Aktuelle Uhrzeit einfügen',
+		'Print': 'Drucken',
+		'Maximize': 'Maximieren',
+		'View source': 'Quelltext ansehen',
+		dateFormat: 'day.month.year'
+	};
+})();

+ 68 - 0
public/js/sc/languages/el.js

@@ -0,0 +1,68 @@
+/**
+ * @author Nikos Aggelis nikosaggelis@hotmail.gr
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['el'] = {
+		'Bold': 'Έντονα',
+		'Italic': 'Πλάγια',
+		'Underline': 'Υπογραμμισμένα',
+		'Strikethrough': 'Διαγραμμισμένα',
+		'Subscript': 'Δείκτης',
+		'Superscript': 'Εκθέτης',
+		'Align left': 'Αριστερή στοίχιση',
+		'Center': 'Κεντραρισμένα',
+		'Align right': 'Δεξιά στοίχιση',
+		'Justify': 'Πλήρης στοίχιση',
+		'Font Name': 'Γραμματοσειρά',
+		'Font Size': 'Μέγεθος',
+		'Font Color': 'Χρώμα',
+		'Remove Formatting': 'Αφαίρεση μορφοποίησης',
+		'Cut': 'Αποκοπή',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Ο περιηγητής σας δεν επιτρέπει την εντολή αποκοπής. Παρακαλούμε χρησιμοποιήστε τη συντόμευση πληκτρολογίου Ctrl/Cmd-X',
+		'Copy': 'Αντιγραφή',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Ο περιηγητής σας δεν επιτρέπει την εντολή αντιγραφής. Παρακαλούμε χρησιμοποιήστε τη συντόμευση πληκτρολογίου Ctrl/Cmd-C',
+		'Paste': 'Επικόλληση',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Ο περιηγητής σας δεν επιτρέπει την εντολή επικόλλησης. Παρακαλούμε χρησιμοποιήστε τη συντόμευση πληκτρολογίου Ctrl/Cmd-V',
+		'Paste your text inside the following box:': 'Επικολλήστε το κείμενό σας μέσα στο ακόλουθο πλαίσιο:',
+		'Paste Text': 'Επικόλληση κειμένου',
+		'Bullet list': 'Λίστα με κουκίδες',
+		'Numbered list': 'Λίστα με αρίθμηση',
+		'Undo': 'Αναίρεση',
+		'Redo': 'Επανάληψη',
+		'Rows:': 'Γραμμές',
+		'Cols:': 'Στήλες',
+		'Insert a table': 'Εισαγωγή πίνακα',
+		'Insert a horizontal rule': 'Εισαγωγή οριζόντιας γραμμής',
+		'Code': 'Κώδικας',
+		'Width (optional):': 'Πλάτος (Προαιρετικό)',
+		'Height (optional):': 'Ύψος (Προαιρετικό)',
+		'Insert an image': 'Εισαγωγή εικόνας',
+		'E-mail:': 'Ηλεκτρονικό ταχυδρομείο',
+		'Insert an email': 'Εισαγωγή email',
+		'URL:': 'Ηλεκτρονική διεύθυνση',
+		'Insert a link': 'Εισαγωγή συνδέσμου',
+		'Unlink': 'Κατάργηση σύνδεσης',
+		'More': 'Περισσότερα',
+		'Insert an emoticon': 'Εισαγωγή φατσούλας',
+		'Video URL:': 'Διεύθυνση βίντεο',
+		'Insert': 'Εισαγωγή',
+		'Insert a YouTube video': 'Εισαγωγή βίντεο YouTube',
+		'Insert current date': 'Εισαγωγή τρέχουσας ημερομηνίας',
+		'Insert current time': 'Εισαγωγή τρέχουσας ώρας',
+		'Print': 'Εκτύπωση',
+		'Maximize': 'Μεγιστοποίηση',
+		'View source': 'Προβολή πηγαίου κώδικα',
+		'Description (optional):': 'Περιγραφή (προαιρετικό)',
+		'Enter the image URL:': 'Εισάγετε τη διεύθυνση εικόνας',
+		'Enter the e-mail address:': 'Εισάγετε τη διεύθυνση e-mail',
+		'Enter the displayed text:': 'Εισάγετε το εμφανιζόμενο κείμενο',
+		'Enter URL:': 'Εισάγετε διεύθυνση',
+		'Enter the YouTube video URL or ID:': 'Εισάγετε τη διεύθυνση του βίντεο YouTube ή το ID',
+		'Insert a Quote': 'Εισαγωγή παράθεσης',
+		'Invalid YouTube video': 'Μη έγκυρο βίντεο YouTube',
+
+		dateFormat: 'day-month-year'
+	};
+})();

+ 7 - 0
public/js/sc/languages/en-US.js

@@ -0,0 +1,7 @@
+(function () {
+	'use strict';
+
+	sceditor.locale['en-US'] = {
+		dateFormat: 'month/day/year'
+	};
+})();

+ 12 - 0
public/js/sc/languages/en.js

@@ -0,0 +1,12 @@
+(function () {
+	'use strict';
+
+	sceditor.locale['en-GB'] = {
+		'Font Color': 'Font Colour',
+		'Center': 'Centre',
+		dateFormat: 'day/month/year'
+	};
+
+	// set this as the default English locale
+	sceditor.locale['en'] = sceditor.locale['en-GB'];
+})();

+ 68 - 0
public/js/sc/languages/es.js

@@ -0,0 +1,68 @@
+/**
+ * @author <Maxpower> <maxpowerid@gmail.com/www.identi.li>
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['es'] = {
+		'Bold': 'Negrita',
+		'Italic': 'Cursiva',
+		'Underline': 'Subrayar',
+		'Strikethrough': 'Tachar',
+		'Subscript': 'Sub\u00edndice',
+		'Superscript': 'Super\u00edndice',
+		'Align left': 'Alinear a la Izquierda',
+		'Center': 'Centrar',
+		'Align right': 'Alinear a la Derecha',
+		'Justify': 'Justificar',
+		'Font Name': 'Tipo de Letra',
+		'Font Size': 'Tama\u00f1o de Letra',
+		'Font Color': 'Color de Fuente',
+		'Remove Formatting': 'Quitar Formatos',
+		'Cut': 'Cortar',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Su navegador no acepta el comando cortar. Por favor, use la combinaci\u00f3n Ctrl/Cmd-X',
+		'Copy': 'Copiar',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Su navegador no acepta el comando copiar. Por favor, use la combinaci\u00f3n Ctrl/Cmd-C',
+		'Paste': 'Pegar',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Su navegador no acepta el comando pegar. Por favor, use la combinaci\u00f3n Ctrl/Cmd-V',
+		'Paste your text inside the following box:': 'Pega el texto dentro del siguiente recuadro',
+		'Paste Text': 'Pegar Texto',
+		'Bullet list': 'Lista de Vi\u00f1etas',
+		'Numbered list': 'Lista Numerada',
+		'Undo': 'Deshacer',
+		'Redo': 'Rehacer',
+		'Rows:': 'Filas',
+		'Cols:': 'Columnas',
+		'Insert a table': 'Insertar una Tabla',
+		'Insert a horizontal rule': 'Insertar una Regla Horizontal',
+		'Code': 'C\u00f3digo',
+		'Width (optional):': 'Ancho (Opcional)',
+		'Height (optional):': 'Altura (Opcional)',
+		'Insert an image': 'Insertar una Imagen',
+		'E-mail:': 'E-mail',
+		'Insert an email': 'Insertar un Email',
+		'URL:': 'URL',
+		'Insert a link': 'Insertar un V\u00ednculo',
+		'Unlink': 'Quitar V\u00ednculo',
+		'More': 'M\u00e1s',
+		'Insert an emoticon': 'Insertar un emoticon',
+		'Video URL:': 'URL del V\u00eddeo',
+		'Insert': 'Insertar',
+		'Insert a YouTube video': 'Insertar un v\u00eddeo de YouTube',
+		'Insert current date': 'Insertar fecha actual',
+		'Insert current time': 'Insertar hora actual',
+		'Print': 'Imprimir',
+		'View source': 'Ver C\u00f3digo',
+		'Description (optional):': 'Descripci\u00f3n (Opcional):',
+		'Enter the image URL:': 'Ingresar la URL de la imagen:',
+		'Enter the e-mail address:': 'Ingresar el correo electr\u00f3nico:',
+		'Enter the displayed text:': 'Ingresar el texto mostrado:',
+		'Enter URL:': 'Ingresar URL:',
+		'Enter the YouTube video URL or ID:': 'Ingresar URL o ID de YouTube',
+		'Insert a Quote': 'Insertar Cita',
+		'Invalid YouTube video': 'Video de YouTube Inv\u00e1lido',
+
+		dateFormat: 'day-month-year'
+	};
+})();

+ 57 - 0
public/js/sc/languages/et.js

@@ -0,0 +1,57 @@
+(function () {
+	'use strict';
+
+	sceditor.locale['et'] = {
+		'Bold': 'Rasvane',
+		'Italic': 'Kaldkiri',
+		'Underline': 'Allajoonitud',
+		'Strikethrough': 'Läbijoonitud',
+		'Subscript': 'Allindeks',
+		'Superscript': 'Ülaindeks',
+		'Align left': 'Joonad vasakule',
+		'Center': 'Joonda keskele',
+		'Align right': 'Joonda paremale',
+		'Justify': 'Joondus mõlemale poole',
+		'Font Name': 'Fondi nimi',
+		'Font Size': 'Fondi suurus',
+		'Font Color': 'Fondi värv',
+		'Remove Formatting': 'Eemalda vormindus',
+		'Cut': 'Lõika',
+		'Sinu veebilehitseja ei luba lõikamise käsu kasutamist. Palun kasuta kiirklahvi Ctrl/Cmd-X': '... Ctrl / Cmd-X',
+		'Copy': 'Kopeeri',
+		'Sinu veebilehitseja ei luba kopeerimise käsu kasutamist. Palun kasuta kiirklahvi Ctrl/Cmd-C': '... Ctrl / Cmd-C',
+		'Paste': 'Aseta',
+		'Sinu veebilehitseja ei luba asetamise käsu kasutamist. Palun kasuta kiirklahvi Ctrl/Cmd-V': '... Ctrl / Cmd-V',
+		'Paste your text inside the following box:': 'Aseta oma tekst järgneva tekstikasti sisse',
+		'Paste Text': 'Aseta tekstina',
+		'Bullet list': 'Nimekiri',
+		'Numbered list': 'Nummerdatud nimekiri',
+		'Undo': 'Samm tagasi',
+		'Redo': 'Samm edasi',
+		'Rows:': 'Read',
+		'Cols:': 'Veerud',
+		'Insert a table': 'Sisesta tabel',
+		'Insert a horizontal rule': 'Sisesta horisontaalne joon',
+		'Code': 'Kood',
+		'Insert a Quote': 'Sisesta tsitaat',
+		'Width (optional):': 'Laius (Valikuline)',
+		'Height (optional):': 'Kõrgus (Valikuline)',
+		'Insert an image': 'Sisesta pilt',
+		'E-mail:': 'E-post',
+		'Insert an email': 'Sisesta e-posti aadress',
+		'URL:': 'Link',
+		'Insert a link': 'Sisesta link',
+		'Unlink': 'Eemalda link',
+		'More': 'Veel',
+		'Insert an emoticon': 'Sisesta emotikon',
+		'Video URL:': 'Video link',
+		'Insert': 'Sisesta',
+		'Insert a YouTube video': 'Sisesta YouTube video',
+		'Insert current date': 'Sisesta praegune kuupäev',
+		'Insert current time': 'Sisesta praegune kellaaeg',
+		'Print': 'Prindi',
+		'View source': 'Vaata lähtekoodi',
+
+		dateFormat: 'day.month.year'
+	};
+})();

+ 69 - 0
public/js/sc/languages/fa.js

@@ -0,0 +1,69 @@
+// add locale:'fa', to your config options.
+// Translated By Ebad Ghafoory [info@ghafoory.com]
+// 2013/05/01
+(function () {
+	'use strict';
+
+	sceditor.locale['fa'] = {
+		'Bold': 'تیره',
+		'Italic': 'مورب',
+		'Underline': 'زیرخط',
+		'Strikethrough': 'خط خورده',
+		'Subscript': 'زیرنویس',
+		'Superscript': 'بالانویس',
+		'Align left': 'چپ چین',
+		'Center': 'وسط چین',
+		'Align right': 'راست چین',
+		'Justify': 'همخط',
+		'Font Name': 'نام قلم',
+		'Font Size': 'اندازه\u200cی نوشته',
+		'Font Color': 'رنگ نوشته',
+		'Remove Formatting': 'پاکسازی فرمت نوشته',
+		'Cut': 'برش',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'مرورگر شما اجازه برش توسط نرم\u200cافزار را نمی\u200cدهد. لطفا از دکمه\u200cهای ترکیبی Ctrl / Cmd-X استفاده کنید',
+		'Copy': 'کپی',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'مرورگر شما اجازه کپی کردن توسط نرم\u200cافزار را نمی\u200cدهد. لطفا از دکمه\u200cهای ترکیبی  Ctrl / Cmd-C استفاده کنید',
+		'Paste': 'چسباندن',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'مرورگر شما اجازه چسباندن توسط نرم\u200cافزار را نمی\u200cدهد. لطفا از دکمه\u200cهای ترکیبی  Ctrl / Cmd-V استفاده کنید',
+		'Paste your text inside the following box:': 'متن خود را در داخل کادر زیر بچسبانید',
+		'Paste Text': 'چسباندن متن',
+		'Bullet list': 'لیست',
+		'Numbered list': 'لیست عددی',
+		'Undo': 'حرکت قبل',
+		'Redo': 'حرکت بعد',
+		'Rows:': 'تعداد ردیف',
+		'Cols:': 'تعداد ستون',
+		'Insert a table': 'افزودن جدول',
+		'Insert a horizontal rule': 'افزودن خط افقی',
+		'Code': 'کد',
+		'Insert a Quote': 'افزودن نقل قول',
+		'Width (optional):': 'پهنا (دلخواه):',
+		'Height (optional):': 'ارتفاع (دلخواه):',
+		'Insert an image': 'افزودن عکس',
+		'E-mail:': 'ایمیل',
+		'Insert an email': 'افزودن ایمیل',
+		'URL:': 'آدرس اینترنتی',
+		'Insert a link': 'افزودن لینک',
+		'Unlink': 'حذف لینک',
+		'More': 'بیشتر',
+		'Insert an emoticon': 'افزودن شکلک',
+		'Video URL:': 'آدرس اینترنتی ویدیو',
+		'Insert': 'افزودن',
+		'Insert a YouTube video': 'افزودن فیلم از یوتوب',
+		'Insert current date': 'افزودن تاریخ اکنون',
+		'Insert current time': 'افزودن زمان اکنون',
+		'Print': 'چاپ',
+		'View source': 'مشاهده سورس',
+		'Description (optional):': 'توضیحات (دلخواه):',
+		'Enter the image URL:': 'آدرس اینترنتی عکس را وارد کنید:',
+		'Enter the e-mail address:': 'آدرس ایمیل را وارد کنید:',
+		'Enter the displayed text:': 'متن نمایش\u200cدهنده را وارد کنید:',
+		'Enter URL:': 'آدرس اینترنتی را وارد کنید:',
+		'Enter the YouTube video URL or ID:': 'آدرس اینترنتی فیلم یوتوب یا شناسه ویدیو را وارد کنید:',
+		'Invalid YouTube video': 'فیلم یوتوب غیر معتبر است',
+		'Right-to-Left': 'راست به چپ',
+		'Left-to-Right': 'چپ به راست',
+
+		dateFormat: 'year.month.day'
+	};
+})();

+ 70 - 0
public/js/sc/languages/fi.js

@@ -0,0 +1,70 @@
+/**
+ * @author Juho Räsänen https://github.com/RJuho
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['fi'] = {
+
+		'Bold': 'Lihavoitu',
+		'Italic': 'Kursivoitu',
+		'Underline': 'Alleviivattu',
+		'Strikethrough': 'Yliviivattu',
+		'Subscript': 'Alaindeksi',
+		'Superscript': 'Yläindeksi',
+		'Align left': 'Tasaa Vasemmalle',
+		'Center': 'Tasaa Keskelle',
+		'Align right': 'Tasaa Oikealle',
+		'Justify': 'Tasaa',
+		'Font Name': 'Fontti',
+		'Font Size': 'Tekstin Koko',
+		'Font Color': 'Tekstin Väri',
+		'Remove Formatting': 'Poista Muotoilu',
+		'Cut': 'Leikkaa',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Selaimesi ei salli leikkaus komentoa. Voit käyttää pikanäppäintä Ctrl/Cmd-X',
+		'Copy': 'Kopioi',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Selaimesi ei salli kopiointi komentoa. Voit käyttää pikanäppäintä Ctrl/Cmd-C',
+		'Paste': 'Liitä',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Selaimesi ei salli liittämis komentoa. Voit käyttää pikanäppäintä Ctrl/Cmd-V',
+		'Paste your text inside the following box:': 'Liitä teksti laatikon sisään:',
+		'Paste Text': 'Liitä Teksti',
+		'Bullet list': 'Lista',
+		'Numbered list': 'Numeroitu Lista',
+		'Undo': 'Kumoa',
+		'Redo': 'Tee Uudelleen',
+		'Rows:': 'Rivit:',
+		'Cols:': 'Sarakkeet:',
+		'Insert a table': 'Lisää taulukko',
+		'Insert a horizontal rule': 'Lisää vaakasuuntainen sääntö',
+		'Code': 'Koodi',
+		'Width (optional):': 'Leveys (valinnainen):',
+		'Height (optional):': 'Korkeus (valinnainen):',
+		'Insert an image': 'Lisää kuva',
+		'E-mail:': 'Sähköpostiosoite:',
+		'Insert an email': 'Syötä sähköpostiosoite',
+		'URL:': 'URL:',
+		'Insert a link': 'Syötä linkki',
+		'Unlink': 'Poista linkitys',
+		'More': 'Lisää',
+		'Insert an emoticon': 'Lisää hymiö',
+		'Video URL:': 'Videon osoite:',
+		'Insert': 'Lisää',
+		'Insert a YouTube video': 'Lisää YouTube-video',
+		'Insert current date': 'Lisää nykyinen päivämäärä',
+		'Insert current time': 'Lisää nykyinen aika',
+		'Print': 'Tulosta',
+		'View source': 'Näytä lähdekoodi',
+		'Description (optional):': 'Kuvaus (valinnainen):',
+		'Enter the image URL:': 'Syötä kuvan URL-osoite:',
+		'Enter the e-mail address:': 'Syötä sähköpostiosoite:',
+		'Enter the displayed text:': 'Syötä näytettävä teksti:',
+		'Enter URL:': 'Anna URL-osoite:',
+		'Enter the YouTube video URL or ID:': 'Anna YouTube-videon URL-osoite tai ID:',
+		'Insert a Quote': 'Lisää lainaus',
+		'Invalid YouTube video': 'Virheellinen YouTube-video',
+		'Drop files here': 'Pudota tiedostot tähän',
+
+		dateFormat: 'day.month.year'
+	};
+})();

+ 70 - 0
public/js/sc/languages/fr.js

@@ -0,0 +1,70 @@
+
+// add locale:'fr', to your config options.
+
+(function () {
+	'use strict';
+
+	sceditor.locale['fr-FR'] = {
+		'Bold': 'Gras',
+		'Italic': 'Italique',
+		'Underline': 'Souligné',
+		'Strikethrough': 'Barré',
+		'Subscript': 'Indice',
+		'Superscript': 'Exposant',
+		'Align left': 'Aligner à gauche',
+		'Center': 'Centrer',
+		'Align right': 'Aligner à droite',
+		'Justify': 'Justifier',
+		'Font Name': 'Police',
+		'Font Size': 'Taille de police',
+		'Font Color': 'Couleur de police',
+		'Remove Formatting': 'Enlever le formatage',
+		'Cut': 'Couper',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Votre navigateur n\'autorise pas la commande \'Couper\'. Merci d\'utiliser le raccourcis clavier Ctrl/Cmd+X',
+		'Copy': 'Copier',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Votre navigateur n\'autorise pas la commande \'Copier\'. Merci d\'utiliser le raccourcis clavier Ctrl/Cmd+C',
+		'Paste': 'Coller',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Votre navigateur n\'autorise pas la commande \'Coller\'. Merci d\'utiliser le raccourcis clavier Ctrl/Cmd+V',
+		'Paste your text inside the following box:': 'Collez votre texte à l\'intérieur de ce bloc',
+		'Paste Text': 'Texte collé',
+		'Bullet list': 'Liste à puce',
+		'Numbered list': 'Liste numérotée',
+		'Undo': 'Annuler',
+		'Redo': 'Rétablir',
+		'Rows:': 'Lignes',
+		'Cols:': 'Colonnes',
+		'Insert a table': 'Insérer un tableau',
+		'Insert a horizontal rule': 'Insérer une ligne horizontale',
+		'Code': 'Code',
+		'Insert a Quote': 'Insérer une citation',
+		'Width (optional):': 'Largeur (Optionnelle)',
+		'Height (optional):': 'Hauteur (Optionnelle)',
+		'Insert an image': 'Insérer une image',
+		'E-mail:': 'Courriel',
+		'Insert an email': 'Insérer un courriel',
+		'URL:': 'URL',
+		'Insert a link': 'Insérer un lien',
+		'Unlink': 'Supprimer un lien',
+		'More': 'Plus',
+		'Insert an emoticon': 'Insérer une émoticône',
+		'Video URL:': 'URL Vidéo',
+		'Insert': 'Insérer',
+		'Insert a YouTube video': 'Insérer une vidéo YouTube',
+		'Insert current date': 'Insérer la date actuelle',
+		'Insert current time': 'Insérer l\'heure actuelle',
+		'Print': 'Imprimer',
+		'View source': 'Afficher le texte brut',
+		'Description (optional):': 'Description (Optionnelle)',
+		'Enter the image URL:': 'Entrez l\'URL de l\'image:',
+		'Enter the e-mail address:': 'Entrez le courriel:',
+		'Enter the displayed text:': 'Entrez le texte affiché:',
+		'Enter URL:': 'Entrez une URL:',
+		'Enter the YouTube video URL or ID:': 'Entrez l\'URL ou l\'ID de la vidéo YouTube:',
+		'Invalid YouTube video': 'Vidéo YouTube invalide',
+		'Right-to-Left': 'De droite à gauche',
+		'Left-to-Right': 'De gauche à droite',
+
+		dateFormat: 'day/month/year'
+	};
+	sceditor.locale['fr'] = sceditor.locale['fr-FR'];
+})();

+ 68 - 0
public/js/sc/languages/gl.js

@@ -0,0 +1,68 @@
+/**
+ * @author Fran Sobrino
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['gl'] = {
+		'Bold': 'Negrita',
+		'Italic': 'Cursiva',
+		'Underline': 'Subrayar',
+		'Strikethrough': 'Riscar',
+		'Subscript': 'Sub\u00edndice',
+		'Superscript': 'Super\u00edndice',
+		'Align left': 'Alinear á Esquerda',
+		'Center': 'Centrar',
+		'Align right': 'Alinear á Dereita',
+		'Justify': 'Xustificar',
+		'Font Name': 'Tipo de Letra',
+		'Font Size': 'Tama\u00f1o de Letra',
+		'Font Color': 'Cor de Fonte',
+		'Remove Formatting': 'Quitar Formatos',
+		'Cut': 'Cortar',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'O seu navegador non acepta o comando cortar. Por favor, empregue a combinaci\u00f3n Ctrl/Cmd-X',
+		'Copy': 'Copiar',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'O seu navegador non acepta o comando cortar. Por favor, empregue a combinaci\u00f3n Ctrl/Cmd-C',
+		'Paste': 'Pegar',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'O seu navegador non acepta o comando cortar. Por favor, empregue a combinaci\u00f3n Ctrl/Cmd-V',
+		'Paste your text inside the following box:': 'Pega o texto dentro do seguinte recadro',
+		'Paste Text': 'Pegar Texto',
+		'Bullet list': 'Lista de Vi\u00f1etas',
+		'Numbered list': 'Lista Numerada',
+		'Undo': 'Desfacer',
+		'Redo': 'Refacer',
+		'Rows:': 'Ringleiras',
+		'Cols:': 'Columnas',
+		'Insert a table': 'Engadir unha Tabla',
+		'Insert a horizontal rule': 'Engadir unha Regla Horizontal',
+		'Code': 'C\u00f3digo',
+		'Width (optional):': 'Ancho (Opcional)',
+		'Height (optional):': 'Altura (Opcional)',
+		'Insert an image': 'Engadir unha Imaxen',
+		'E-mail:': 'E-mail',
+		'Insert an email': 'Engadir un Email',
+		'URL:': 'URL',
+		'Insert a link': 'Engadir un V\u00ednculo',
+		'Unlink': 'Quitar V\u00ednculo',
+		'More': 'M\u00e1is',
+		'Insert an emoticon': 'Engadir un emoticon',
+		'Video URL:': 'URL do V\u00eddeo',
+		'Insert': 'Engadir',
+		'Insert a YouTube video': 'Engadir un v\u00eddeo de YouTube',
+		'Insert current date': 'Engadir data actual',
+		'Insert current time': 'Engadir hora actual',
+		'Print': 'Imprimir',
+		'View source': 'Ver C\u00f3digo',
+		'Description (optional):': 'Descripci\u00f3n (Opcional):',
+		'Enter the image URL:': 'Ingresar a URL da imaxen:',
+		'Enter the e-mail address:': 'Ingresar o correo electr\u00f3nico:',
+		'Enter the displayed text:': 'Ingresar o texto mostrado:',
+		'Enter URL:': 'Ingresar URL:',
+		'Enter the YouTube video URL or ID:': 'Ingresar URL ou ID de YouTube',
+		'Insert a Quote': 'Engadir Cita',
+		'Invalid YouTube video': 'V\u00eddeo de YouTube Inv\u00e1lido',
+
+		dateFormat: 'day-month-year'
+	};
+})();

+ 69 - 0
public/js/sc/languages/hu.js

@@ -0,0 +1,69 @@
+/**
+ * @author Ángyán László <lacavale55@gmail.com>
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ * @date 2013-08-11
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['hu'] = {
+		'Bold': 'Félkövér',
+		'Italic': 'Dőlt',
+		'Underline': 'Aláhúzva',
+		'Strikethrough': 'Áthúzva',
+		'Subscript': 'Alsó index',
+		'Superscript': 'Felső index',
+		'Align left': 'Balra zárt',
+		'Center': 'Középre zárt',
+		'Align right': 'Jobbra zárt',
+		'Justify': 'Sorkizárt',
+		'Font Name': 'Betűtípus',
+		'Font Size': 'Betű méret',
+		'Font Color': 'Betű szín',
+		'Remove Formatting': 'Formázás törlése',
+		'Cut': 'Kivágás',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'A böngésző biztonsági beállításai nem engedik a kivágást. Használd a Ctrl/Cmd+X billetyűket.',
+		'Copy': 'Másolás',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'A böngésző biztonsági beállításai nem engedik a másolást. Használd a Ctrl/Cmd+C billetyűket.',
+		'Paste': 'Beillesztés',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'A böngésző biztonsági beállításai nem engedik a beillesztést. Használd a Ctrl/Cmd+V billetyűket.',
+		'Paste your text inside the following box:': 'Illeszd be a szöveget a dobozba:',
+		'Paste Text': 'Szöveg beszúrása',
+		'Bullet list': 'Felsorolás',
+		'Numbered list': 'Sorszámozott felsorolás',
+		'Undo': 'Vissza',
+		'Redo': 'Mégis',
+		'Rows:': 'Sorok',
+		'Cols:': 'Oszlopok',
+		'Insert a table': 'Táblázat beszúrása',
+		'Insert a horizontal rule': 'Vízszintes vonal beszúrása',
+		'Code': 'Kód',
+		'Width (optional):': 'Szélesség (nem kötelező):',
+		'Height (optional):': 'Magasság (nem kötelező):',
+		'Insert an image': 'Illessz be egy képet',
+		'E-mail:': 'Email:',
+		'Insert an email': 'Illessz be egy email címet.',
+		'URL:': 'Honlap',
+		'Insert a link': 'Hivatkozás létrehozása',
+		'Unlink': 'Hivatkozás megszüntetése',
+		'More': 'Több',
+		'Insert an emoticon': 'Smiley beszúrása',
+		'Video URL:': 'Video link:',
+		'Insert': 'Beszúrás',
+		'Insert a YouTube video': 'Youtube video beszúrása',
+		'Insert current date': 'Szúrd be az aktuális dátumot',
+		'Insert current time': 'Szúrd be a jelenlegi időt',
+		'Print': 'Nyomtatás',
+		'View source': 'Forrás',
+		'Description (optional):': 'Hivatkozás szövege (nem kötelező)',
+		'Enter the image URL:': 'Kép URL beillesztése:',
+		'Enter the e-mail address:': 'Írd be az email címet:',
+		'Enter the displayed text:': 'Írd be a megjelenítendő szöveget:',
+		'Enter URL:': 'Írd be a linket:',
+		'Enter the YouTube video URL or ID:': 'Írd be a Youtube video URL-jét vagy azonosítóját',
+		'Insert a Quote': 'Idézet beszúrása',
+		'Invalid YouTube video': 'Érvénytelen Youtube link',
+
+		dateFormat: 'year.month.day.'
+	};
+})();

+ 68 - 0
public/js/sc/languages/id.js

@@ -0,0 +1,68 @@
+/**
+ * @author Sandy Irawan (sndbkct@gmail.com)
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['id'] = {
+		'Bold': 'Tebal',
+		'Italic': 'Miring',
+		'Underline': 'Garis Bawah',
+		'Strikethrough': 'Coret',
+		'Subscript': 'Tulisan dibawah garis',
+		'Superscript': 'Tulisan diatas garis',
+		'Align left': 'Rata Kiri',
+		'Center': 'Rata Tengah',
+		'Align right': 'Rata Kanan',
+		'Justify': 'Rata Kanan-Kiri',
+		'Font Name': 'Nama Fon',
+		'Font Size': 'Ukuran Fon',
+		'Font Color': 'Warna Fon',
+		'Remove Formatting': 'Hapus Format',
+		'Cut': 'Potong',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Browser Anda tidak memungkinkan perintah cut. Silakan gunakan shortcut keyboard Ctrl / Cmd-X ',
+		'Copy': 'Salin',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Browser Anda tidak memungkinkan perintah copy. Silakan gunakan shortcut keyboard Ctrl / Cmd-C ',
+		'Paste': 'Rekatkan',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Browser Anda tidak memungkinkan perintah paste. Silakan gunakan shortcut keyboard Ctrl / Cmd-V ',
+		'Paste your text inside the following box:': 'Rekatkan teks Anda dalam kotak berikut:',
+		'Paste Text': 'Rekatkan Teks',
+		'Bullet list': 'Daftar Bullet',
+		'Numbered list': 'Daftar Nomor',
+		'Undo': 'Kembalikan',
+		'Redo': 'Ulangi',
+		'Rows:': 'Baris',
+		'Cols:': 'Kolom',
+		'Insert a table': 'Sisipkan sebuah tabel',
+		'Insert a horizontal rule': 'Sisipkan aturan horisontal',
+		'Code': 'Kode',
+		'Width (optional):': 'Lebar (opsional)',
+		'Height (optional):': 'Tinggi (opsional)',
+		'Insert an image': 'Sisipkan Gambar',
+		'E-mail:': 'Surel',
+		'Insert an email': 'Sisipkan surel',
+		'URL:': 'URL',
+		'Insert a link': 'Sisipkan link',
+		'Unlink': 'Buang Link',
+		'More': 'Lainnya',
+		'Insert an emoticon': 'Sisipkan emotikon',
+		'Video URL:': 'URL Video',
+		'Insert': 'Sisipkan',
+		'Insert a YouTube video': 'Sisipkan video Youtube',
+		'Insert current date': 'Sisipkan tanggal sekarang',
+		'Insert current time': 'Sisipkan waktu sekarang',
+		'Print': 'Print',
+		'View source': 'Lihat sumber',
+		'Description (optional):': 'Deskripsi (opsional)',
+		'Enter the image URL:': 'Masukkan URL gambar',
+		'Enter the e-mail address:': 'Masukkan alamat surel',
+		'Enter the displayed text:': 'Masukkan teks yang ditampilkan',
+		'Enter URL:': 'Masukkan URL',
+		'Enter the YouTube video URL or ID:': 'Masukkan URL video YouTube atau ID',
+		'Insert a Quote': 'Sisipkan kutipan',
+		'Invalid YouTube video': 'Video YouTube yang tidak valid',
+
+		dateFormat: 'day-month-year'
+	};
+})();

+ 72 - 0
public/js/sc/languages/it.js

@@ -0,0 +1,72 @@
+/**
+ * @author <Tropico> <www.mangiaconsapevole.com>
+ * @author Gianluca Guazzo
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['it-IT'] = {
+		'Bold': 'Grassetto',
+		'Italic': 'Corsivo',
+		'Underline': 'Sottolineato',
+		'Strikethrough': 'Barrato',
+		'Subscript': 'Pedice',
+		'Superscript': 'Apice',
+		'Align left': 'Allinea a sinistra',
+		'Center': 'Centrato',
+		'Align right': 'Allinea a destra',
+		'Justify': 'Giustificato',
+		'Font Name': 'Nome carattere',
+		'Font Size': 'Dimensione carattere',
+		'Font Color': 'Colore carattere',
+		'Remove Formatting': 'Rimuovi formattazione',
+		'Cut': 'Taglia',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Il tuo browser non permette il comando Taglia. Usa per favore la scorciatoia da tastiera Ctrl/Cmd-X',
+		'Copy': 'Copia',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Il tuo browser non permette il comando Copia. Usa per favore la scorciatoia da tastiera Ctrl/Cmd-C',
+		'Paste': 'Incolla',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Il tuo browser non permette il comando Incolla. Usa per favore la scorciatoia da tastiera Ctrl/Cmd-V',
+		'Paste your text inside the following box:': 'Incolla il tuo testo dentro il seguente riquadro',
+		'Paste Text': 'Incolla Testo',
+		'Bullet list': 'Elenco puntato',
+		'Numbered list': 'Elenco numerato',
+		'Undo': 'Annulla',
+		'Redo': 'Ripeti',
+		'Rows:': 'Righe:',
+		'Cols:': 'Colonne:',
+		'Insert a table': 'Inserisci una tabella',
+		'Insert a horizontal rule': 'Inserisci riga orizzontale',
+		'Code': 'Codice',
+		'Width (optional):': 'Larghezza(opzionale):',
+		'Height (optional):': 'Altezza(opzionale):',
+		'Insert an image': 'Inserisci un\'immagine',
+		'E-mail:': 'E-mail:',
+		'Insert an email': 'Inserisci una email',
+		'URL:': 'URL:',
+		'Insert a link': 'Inserisci collegamento(link):',
+		'Unlink': 'Togli collegamento(link):',
+		'More': 'Di più',
+		'Insert an emoticon': 'Inserisci una emoticon',
+		'Video URL:': 'URL del video',
+		'Insert': 'Inserisci',
+		'Insert a YouTube video': 'Inserisci un video YouTube',
+		'Insert current date': 'Inserisci data corrente',
+		'Insert current time': 'Inserisci ora corrente',
+		'Print': 'Stampa',
+		'View source': 'Vedi codice sorgente',
+		'Description (optional):': 'Descrizione (opzionale):',
+		'Enter the image URL:': 'Inserisci URL dell\'immagine',
+		'Enter the e-mail address:': 'Inserisci indirizzo email',
+		'Enter the displayed text:': 'Inserisci testo visualizzato',
+		'Enter URL:': 'Inserisci URL',
+		'Enter the YouTube video URL or ID:': 'Inserisci URL o ID video di YouTube',
+		'Insert a Quote': 'Inserisci una citazione',
+		'Invalid YouTube video': 'Video YouTube invalido',
+
+		dateFormat: 'day-month-year'
+	};
+
+	// Set as the default Italian locale
+	sceditor.locale['it'] = sceditor.locale['it-IT'];
+})();

+ 71 - 0
public/js/sc/languages/ja.js

@@ -0,0 +1,71 @@
+/**
+ * @author <Yoshihiro Misawa> <myoshi321go@gmail.com>
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['ja'] = {
+		'Bold': '太字',
+		'Italic': '斜字',
+		'Underline': '下線',
+		'Strikethrough': '取り消し線',
+		'Subscript': '下付き文字',
+		'Superscript': '上付き文字',
+		'Align left': '左揃え',
+		'Center': '中央揃え',
+		'Align right': '右揃え',
+		'Justify': '均等揃え',
+		'Font Name': 'フォント名',
+		'Font Size': 'フォントサイズ',
+		'Font Color': 'フォントの色',
+		'Remove Formatting': '書式解除',
+		'Cut': '切り取り',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'お使いのブラウザではカットコマンドを許可されていません。 キーボードショートカットの Ctrl/Cmd-X をお使いください。',
+		'Copy': 'コピー',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'お使いのブラウザではコピーコマンドを許可されていません。 キーボードショートカットの Ctrl/Cmd-C をお使いください。',
+		'Paste': '貼り付け',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'お使いのブラウザでは貼り付けコマンドを許可されていません。 キーボードショートカットの Ctrl/Cmd-V をお使いください。',
+		'Paste your text inside the following box:': '以下にテキストを貼り付けてください。',
+		'Paste Text': 'テキストを貼り付け',
+		'Bullet list': '箇条書き',
+		'Numbered list': '段落番号',
+		'Undo': '元に戻す',
+		'Redo': 'やり直す',
+		'Rows:': '行数',
+		'Cols:': '列数',
+		'Insert a table': '表を挿入',
+		'Insert a horizontal rule': '水平線を挿入',
+		'Code': 'コード',
+		'Width (optional):': '幅 (オプション)',
+		'Height (optional):': '高さ (オプション)',
+		'Insert an image': '画像を挿入',
+		'E-mail:': 'メールアドレス',
+		'Insert an email': 'メールアドレスを挿入',
+		//'URL:': ',
+		'Insert a link': 'リンクを挿入',
+		'Unlink': 'リンクを解除',
+		//'More': ',
+		'Insert an emoticon': '顔文字を挿入',
+		'Video URL:': '動画URL',
+		'Insert': '挿入',
+		'Insert a YouTube video': 'Youtubeを挿入',
+		'Insert current date': '現在の日付を挿入',
+		'Insert current time': '現在の時間を挿入',
+		'Print': '印刷',
+		'View source': 'ソースを表示',
+		'Description (optional):': '説明 (オプション)',
+		'Enter the image URL:': '画像URLを入力してください。',
+		'Enter the e-mail address:': 'メールアドレスを入力してください。',
+		'Enter the displayed text:': '表示テキストを入力してください。',
+		'Enter URL:': 'URLを入力してください。',
+		'Enter the YouTube video URL or ID:': 'Youtubeの動画URLまたはIDを入力してください。',
+		'Insert a Quote': '引用を挿入',
+		'Invalid YouTube video': '不正なYoutube動画',
+		'Left-to-Right': '左から右へ',
+		'Right-to-Left': '右から左へ',
+		'Maximize': '最大化',
+
+		dateFormat: 'year-month-day'
+	};
+})();

+ 68 - 0
public/js/sc/languages/lt.js

@@ -0,0 +1,68 @@
+/**
+ * @author Team from www.klaustukai.lt
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['lt'] = {
+		'Bold': 'Paryškintas',
+		'Italic': 'Pasvirasis',
+		'Underline': 'Pabraukti',
+		'Strikethrough': 'Perbraukti',
+		'Subscript': 'Parašyti sumažintas raides po žodžio',
+		'Superscript': 'Parašyti sumažintas raides virš žodžio',
+		'Align left': 'Kairysis lygiavimas',
+		'Center': 'Centrinis lygiavimas',
+		'Align right': 'Dešinysis lygiavimas',
+		'Justify': 'Išlygintas tekstas',
+		'Font Name': 'Šrifto pavadinimas',
+		'Font Size': 'Šrifto dydis',
+		'Font Color': 'Šrifto spalva',
+		'Remove Formatting': 'Panaikinti teksto formatavimą',
+		'Cut': 'Iškirpti',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Jūsų paieškos sistema neleidžia atlikti šios funkcijos. Norėdami iškirpti spauskite Ctrl/Cmd-x',
+		'Copy': 'Kopijuoti',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Jūsų paieškos sistema neleidžia atlikti šios komandos. Norėdami nukopijuoti spauskite Ctrl/Cmd - C',
+		'Paste': 'Įklijuoti',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Jūsų paieškos sistema neleidžia atlikti šios komandos. Norėdami įklijuoti spauskite Ctrl/Cmd - V',
+		'Paste your text inside the following box:': 'Įklijuokite tekstą nurodytoje vietoje',
+		'Paste Text': 'Įklijuoti tekstą',
+		'Bullet list': 'Sugrupuotas sąrašas',
+		'Numbered list': 'Sunumeruotas sąrašas',
+		'Undo': 'panaikinti',
+		'Redo': 'atitaisyti',
+		'Rows:': 'Eilutės',
+		'Cols:': 'Stulpeliai',
+		'Insert a table': 'Įterpti lentelę',
+		'Insert a horizontal rule': 'Įterpti horizontalią liniją',
+		'Code': 'Šalies kodas',
+		'Width (optional):': 'plotis (laisvai pasirenkamas)',
+		'Height (optional):': 'aukštis (laisvai pasirenkamas)',
+		'Insert an image': 'Įterpti nuotrauką',
+		'E-mail:': 'Elektroninis paštas',
+		'Insert an email': 'Įterpti elktroninio pašto nuorodą',
+		'URL:': 'Internetinės svetainės adresas:',
+		'Insert a link': 'Įterpti nuorodą',
+		'Unlink': 'Atjungti',
+		'More': 'Daugiau',
+		'Insert an emoticon': 'Įterpti šypsenėlę',
+		'Video URL:': 'Vaizdo klipo nuoroda',
+		'Insert': 'Įterpti',
+		'Insert a YouTube video': 'Įterpti Youtube vaizdo klipą',
+		'Insert current date': 'Įterpti esamą datą (diena-mėnuo-metai)',
+		'Insert current time': 'Įterpti esamą laiką',
+		'Print': 'Atspausdinti',
+		'View source': 'Peržiūrėti šaltinį',
+		'Description (optional):': 'Aprašymas (laisvai pasirenkamas)',
+		'Enter the image URL:': 'Įterpti nuotraukos adresą',
+		'Enter the e-mail address:': 'Įterpti elektroninio pašto adresą',
+		'Enter the displayed text:': 'Įvesti pavaizduotą tekstą',
+		'Enter URL:': 'Įvesti internetinį adresą',
+		'Enter the YouTube video URL or ID:': 'Įrašykite Youtube vaizdo klipo nuorodą ar ID',
+		'Insert a Quote': 'Įterpti citatą',
+		'Invalid YouTube video': 'YouTube vaizdo įrašas neveikia',
+
+		dateFormat: 'year-month-day'
+	};
+})();

+ 70 - 0
public/js/sc/languages/nb.js

@@ -0,0 +1,70 @@
+/**
+ * @author Katrine
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['nb-NO'] = {
+		'Bold': 'Fet',
+		'Italic': 'Kursiv',
+		'Underline': 'Understrek',
+		'Strikethrough': 'Gjennomstrek',
+		'Subscript': 'Senket',
+		'Superscript': 'Hevet',
+		'Align left': 'Sidestill til venstre',
+		'Center': 'Midstill',
+		'Align right': 'Sidestill til høyre',
+		'Justify': 'Normalt oppstilt',
+		'Font Name': 'Skriftype',
+		'Font Size': 'Skriftstørrelse',
+		'Font Color': 'skriftfarge',
+		'Remove Formatting': 'Fjern formatering',
+		'Cut': 'Klipp',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Nettleseren din kan ikke utføre klippe kommandoen. Vennligst bruk hurtigtasten Ctrl / Cmd-X',
+		'Copy': 'Kopier',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Nettleseren din kan ikke utføre kopier kommandoen. Vennligst bruk hurtigtasten Ctrl / Cmd-C',
+		'Paste': 'Lim',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Nettleseren din kan ikke utføre lime kommandoen. Vennligst bruk hurtigtasten Ctrl / Cmd-V',
+		'Paste your text inside the following box:': 'Lim inn teksten i den følgende boksen:',
+		'Paste Text': 'Lim inn tekst',
+		'Bullet list': 'Bullet liste',
+		'Numbered list': 'Nummerert liste',
+		'Undo': 'Angre',
+		'Redo': 'Gjør på nytt',
+		'Rows:': 'Rader',
+		'Cols:': 'Kolonner',
+		'Insert a table': 'Sett inn en tabell',
+		'Insert a horizontal rule': 'Sett en horisontal regel',
+		'Code': 'Kode',
+		'Width (optional):': 'Bredde (valgfritt):',
+		'Height (optional):': 'Høyde (valgfritt):',
+		'Insert an image': 'Sett inn et bilde',
+		'E-mail:': 'E-post',
+		'Insert an email': 'Sett inn en e-post',
+		'URL:': 'URL:',
+		'Insert a link': 'Sett inn en lenke',
+		'Unlink': 'Oppheve tilknytningen',
+		'More': 'Mer',
+		'Insert an emoticon': 'Sett inn et uttrykksikon',
+		'Video URL:': 'Video URL',
+		'Insert': 'Sett inn',
+		'Insert a YouTube video': 'Sett inn en YouTube-video',
+		'Insert current date': 'Sett inn gjeldende dato',
+		'Insert current time': 'Sett inn gjeldende klokkeslett',
+		'Print': 'Skriv ut',
+		'View source': 'Vis kildekode',
+		'Description (optional):': 'Beskrivelse (valgfritt):',
+		'Enter the image URL:': 'Skriv inn bildet\'s URL:',
+		'Enter the e-mail address:': 'Skriv inn e-postadresse:',
+		'Enter the displayed text:': 'Skriv inn teksten som vises:',
+		'Enter URL:': 'Skriv inn URL adresse:',
+		'Enter the YouTube video URL or ID:': 'Angi YouTube video link eller ID:',
+		'Insert a Quote': 'Sett inn sitat',
+		'Invalid YouTube video': 'Ugyldig Youtube video',
+
+		dateFormat: 'day.month.year'
+	};
+
+	sceditor.locale['nb'] = sceditor.locale['nb-NO'];
+})();

+ 72 - 0
public/js/sc/languages/nl.js

@@ -0,0 +1,72 @@
+/**
+ * @author Pieterjan Deneys (NekoJonez) - https://arpegi.wordpress.com
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+
+(function () {
+	'use strict';
+
+	sceditor.locale['nl'] = {
+		'Bold': 'Vet',
+		'Italic': 'Cursief',
+		'Underline': 'Onderlijnd',
+		'Strikethrough': 'Doorhalen',
+		'Subscript': 'Subscript',
+		'Superscript': 'Superscript',
+		'Align left': 'Links uitlijnen',
+		'Center': 'Centreren',
+		'Align right': 'Rechts uitlijnen',
+		'Justify': 'Uitvullen',
+		'Font Name': 'Lettertype naam',
+		'Font Size': 'Lettergrootte',
+		'Font Color': 'Lettertype kleur',
+		'Remove Formatting': 'Verwijder opmaak',
+		'Cut': 'Knippen',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Je browser staat het knippen commando niet toe. Gebruik de toetsenbord sneltoets Ctrl/Cmd-X',
+		'Copy': 'Kopiëren',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Je browser staat het kopieer commando niet toe. Gebruik de toetsenbord sneltoets Ctrl/Cmd-C',
+		'Paste': 'Plakken',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Je browser staat het plakken commando niet toe. Gebruik de toetsenbord sneltoets Ctrl/Cmd-V',
+		'Paste your text inside the following box:': 'Plak je tekst in het volgende vak:',
+		'Paste Text': 'Tekst plakken',
+		'Bullet list': 'Opsomming',
+		'Numbered list': 'Genummerde lijst',
+		'Undo': 'Ongedaan maken',
+		'Redo': 'Opnieuw uitvoeren',
+		'Rows:': 'Rijen',
+		'Cols:': 'Kolommen',
+		'Insert a table': 'Tabel',
+		'Insert a horizontal rule': 'Horizontale regel invoegen',
+		'Code': 'Code',
+		'Width (optional):': 'Breedte (optioneel):',
+		'Height (optional):': 'Hoogte (optioneel):',
+		'Insert an image': 'Afbeelding invoegen',
+		'E-mail:': 'E-mail',
+		'Insert an email': 'E-mail invoegen',
+		'URL:': 'URL:',
+		'Insert a link': 'Link invoegen',
+		'Unlink': 'Link verwijderen',
+		'More': 'Meer',
+		'Insert an emoticon': 'Emoticon invoegen',
+		'Video URL:': 'Video URL',
+		'Insert': 'Invoegen',
+		'Insert a YouTube video': 'YouTube video invoegen',
+		'Insert current date': 'Huidige datum invoegen',
+		'Insert current time': 'Huidige tijd invoegen',
+		'Print': 'Print',
+		'View source': 'Bron bekijken',
+		'Description (optional):': 'Beschrijving (optioneel):',
+		'Enter the image URL:': 'Voer de afbeelding URL in:',
+		'Enter the e-mail address:': 'Voer het e-mailadres in:',
+		'Enter the displayed text:': 'Voer de getoonde tekst in:',
+		'Enter URL:': 'Voer de URL in:',
+		'Enter the YouTube video URL or ID:': 'Voer de YouTube video URL of ID in:',
+		'Insert a Quote': 'Citaat toevoegen',
+		'Invalid YouTube video': 'Ongeldige YouTube video',
+		'Drop files here': 'Plaats bestanden hier',
+
+		// month format, replace - with the date format separator and order in the
+		// order used
+		dateFormat: 'day-month-year'
+	};
+})();

+ 68 - 0
public/js/sc/languages/pl.js

@@ -0,0 +1,68 @@
+/**
+ * @author <Mirosław Dróżdż> <miroslaw.drozdz@vert.pl/www.vert.info.pl>
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['pl'] = {
+		'Bold': 'Pogrubienie',
+		'Italic': 'Kursywa',
+		'Underline': 'Podkreślenie',
+		'Strikethrough': 'Przekreślenie',
+		'Subscript': 'Indeks dolny',
+		'Superscript': 'Indeks górny',
+		'Align left': 'Do lewej',
+		'Center': 'Do środka',
+		'Align right': 'Do prawej',
+		'Justify': 'Wyjustowanie',
+		'Font Name': 'Krój czcionki',
+		'Font Size': 'Rozmiar czcionki',
+		'Font Color': 'Kolor czcionki',
+		'Remove Formatting': 'Usuń formatowanie',
+		'Cut': 'Wytnij',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Twoja przeglądarka nie obsługuje opcji wycinania. Użyj skrótu klawiszowego Cmd/Ctrl + X',
+		'Copy': 'Skopiuj',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Twoja przeglądarka nie obsługuje opcji kopiowania. Użyj skrótu klawiszowego Cmd/Ctrl + C',
+		'Paste': 'Wklej',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Twoja przeglądarka nie obsługuje opcji wklejania. Użyj skrótu klawiszowego Cmd/Ctrl + V',
+		'Paste your text inside the following box:': 'Wklej swój tekst do tego pola:',
+		'Paste Text': 'Wklej tekst',
+		'Bullet list': 'Wypunktowanie',
+		'Numbered list': 'Lista numerowana',
+		'Undo': 'Cofnij',
+		'Redo': 'Powtórz',
+		'Rows:': 'Wiersze:',
+		'Cols:': 'Kolumny:',
+		'Insert a table': 'Wstaw tabelę',
+		'Insert a horizontal rule': 'Wstaw linię poziomą',
+		'Code': 'Kod',
+		'Width (optional):': 'Szerokość (opcjonalnie)',
+		'Height (optional):': 'Wysokość (opcjonalnie)',
+		'Insert an image': 'Wstaw obrazek',
+		'E-mail:': 'E-mail',
+		'Insert an email': 'Wstaw e-mail',
+		'URL:': 'URL',
+		'Insert a link': 'Wstaw odnośnik',
+		'Unlink': 'Usuń odnośnik',
+		'More': 'Więcej',
+		'Insert an emoticon': 'Wstaw emotikonę',
+		'Video URL:': 'URL do filmu',
+		'Insert': 'Wstaw',
+		'Insert a YouTube video': 'Wstaw film YouTube',
+		'Insert current date': 'Wstaw aktualną datę',
+		'Insert current time': 'Wstaw aktualny czas',
+		'Print': 'Drukuj',
+		'View source': 'Pokaż źródło',
+		'Description (optional):': 'Opis (opcjonalny)',
+		'Enter the image URL:': 'Wstaw URL do obrazka',
+		'Enter the e-mail address:': 'Wpisz adres e-mail',
+		'Enter the displayed text:': 'Wpisz wyświetlony tekst',
+		'Enter URL:': 'Wpisz adres URL',
+		'Enter the YouTube video URL or ID:': 'Wpisz adres URL lub ID filmu na YouTube',
+		'Insert a Quote': 'Wstaw cytat',
+		'Invalid YouTube video': 'Nieprawidłowy film YouTube',
+
+		dateFormat: 'day-month-year'
+	};
+})();

+ 67 - 0
public/js/sc/languages/pt-BR.js

@@ -0,0 +1,67 @@
+/**
+* @author martec
+* @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+*/
+(function () {
+	'use strict';
+
+	sceditor.locale['pt-BR'] = {
+		'Bold': 'Negrito',
+		'Italic': 'Itálico',
+		'Underline': 'Sublinhado',
+		'Strikethrough': 'Rasurado',
+		'Subscript': 'Subscrito',
+		'Superscript': 'Sobrescrito ',
+		'Align left': 'Alinhar à esquerda',
+		'Center': 'Centralizar',
+		'Align right': 'Alinhar à direita',
+		'Justify': 'Justificar',
+		'Font Name': 'Nome da fonte',
+		'Font Size': 'Tamanho da fonte',
+		'Font Color': 'Cor da fonte',
+		'Remove Formatting': 'Remover a formatação',
+		'Cut': 'Recortar',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Seu navegador não permite o comando recortar. Favor use o atalho Ctrl/Cmd-X',
+		'Copy': 'Copiar',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Seu navegador não permite o comando copiar. Favor use o atalho Ctrl/Cmd-C',
+		'Paste': 'Colar',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Seu navegador não permite o comando colar. Favor use o atalho Ctrl/Cmd-V',
+		'Paste your text inside the following box:': 'Cole o seu texto dentro da caixa de texto a seguir:',
+		'Paste Text': 'Colar o texto',
+		'Bullet list': 'Lista com marcadores',
+		'Numbered list': 'Lista numérica',
+		'Undo': 'Desfazer',
+		'Redo': 'Refazer',
+		'Rows:': 'Linhas:',
+		'Cols:': 'Colunas:',
+		'Insert a table': 'Inserir uma tabela',
+		'Insert a horizontal rule': 'Inserir uma linha horizontal',
+		'Code': 'Código',
+		'Width (optional):': 'Largura (opcional):',
+		'Height (optional):': 'Altura (opcional):',
+		'Insert an image': 'Inserir uma imagem',
+		'E-mail:': 'E-mail:',
+		'Insert an email': 'Inserir um e-mail',
+		'URL:': 'URL:',
+		'Insert a link': 'Inserir um hiperlink',
+		'Unlink': 'Remover o hiperlink',
+		'More': 'Mais',
+		'Insert an emoticon': 'Inserir um emoticon',
+		'Video URL:': 'Video URL:',
+		'Insert': 'Inserir',
+		'Insert a YouTube video': 'Inserir YouTube video',
+		'Insert current date': 'Inserir a data atual',
+		'Insert current time': 'Inserir a hora atual',
+		'Print': 'Imprimir',
+		'View source': 'Fonte',
+		'Description (optional):': 'Descrição (opcional):',
+		'Enter the image URL:': 'Informe o endereço URL da imagem:',
+		'Enter the e-mail address:': 'Informe o endereço de e-mail:',
+		'Enter the displayed text:': 'Digite o texto exibido:',
+		'Enter URL:': 'Informe o endereço URL:',
+		'Enter the YouTube video URL or ID:': 'Informe o endereço URL ou ID do YouTube:',
+		'Insert a Quote': 'Inserir uma citação',
+		'Invalid YouTube video': 'Vídeo do YouTube inválido',
+		dateFormat: 'day-month-year'
+	};
+})();

+ 69 - 0
public/js/sc/languages/pt.js

@@ -0,0 +1,69 @@
+/**
+* @author brunoais
+* @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+*/
+(function () {
+	'use strict';
+
+	sceditor.locale['pt-PT'] = {
+		'Bold': 'Negrito',
+		'Italic': 'Itálico',
+		'Underline': 'Sublinhado',
+		'Strikethrough': 'Rasurado',
+		'Subscript': 'Subscrito',
+		'Superscript': 'Sobrescrito ',
+		'Align left': 'Alinhar à esquerda',
+		'Center': 'Centrar',
+		'Align right': 'Alinhar à direita',
+		'Justify': 'Justificar',
+		'Font Name': 'Nome da fonte',
+		'Font Size': 'Tamanho da fonte',
+		'Font Color': 'Cor da fonte',
+		'Remove Formatting': 'Remover a formatação',
+		'Cut': 'Cortar',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Seu navegador não permite o comando cortar. Por favor use o atalho Ctrl/Cmd-X',
+		'Copy': 'Copiar',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Seu navegador não permite o comando copiar. Por favor  use o atalho Ctrl/Cmd-C',
+		'Paste': 'Colar',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Seu navegador não permite o comando colar. Por favor  use o atalho Ctrl/Cmd-V',
+		'Paste your text inside the following box:': 'Cole o seu texto dentro da caixa de texto a seguir:',
+		'Paste Text': 'Colar o texto',
+		'Bullet list': 'Lista com marcadores',
+		'Numbered list': 'Lista numérica',
+		'Undo': 'Desfazer',
+		'Redo': 'Refazer',
+		'Rows:': 'Linhas:',
+		'Cols:': 'Colunas:',
+		'Insert a table': 'Inserir uma tabela',
+		'Insert a horizontal rule': 'Inserir uma linha horizontal',
+		'Code': 'Código',
+		'Width (optional):': 'Largura (opcional):',
+		'Height (optional):': 'Altura (opcional):',
+		'Insert an image': 'Inserir uma imagem',
+		'E-mail:': 'E-mail:',
+		'Insert an email': 'Inserir um e-mail',
+		'URL:': 'URL:',
+		'Insert a link': 'Inserir um hiperlink',
+		'Unlink': 'Remover o hiperlink',
+		'More': 'Mais',
+		'Insert an emoticon': 'Inserir um emoticon',
+		'Video URL:': 'Video URL:',
+		'Insert': 'Inserir',
+		'Insert a YouTube video': 'Inserir YouTube video',
+		'Insert current date': 'Inserir a data atual',
+		'Insert current time': 'Inserir a hora atual',
+		'Print': 'Imprimir',
+		'View source': 'Código fonte',
+		'Description (optional):': 'Descrição (opcional):',
+		'Enter the image URL:': 'Introduza o endereço URL da imagem:',
+		'Enter the e-mail address:': 'Introduza o endereço de e-mail:',
+		'Enter the displayed text:': 'Indique o texto exibido:',
+		'Enter URL:': 'Introduza o endereço URL:',
+		'Enter the YouTube video URL or ID:': 'Introduza o endereço URL ou o ID do video do YouTube:',
+		'Insert a Quote': 'Inserir uma citação',
+		dateFormat: 'day/month/year'
+	};
+
+	// Set as the default Portuguese locale
+	sceditor.locale['pt'] = sceditor.locale['pt-PT'];
+})();

+ 60 - 0
public/js/sc/languages/ru.js

@@ -0,0 +1,60 @@
+(function () {
+	'use strict';
+
+	sceditor.locale['ru'] = {
+		'Bold': 'Жирный',
+		'Italic': 'Курсив',
+		'Underline': 'Подчёркнутый',
+		'Strikethrough': 'Зачёркнутый',
+		'Subscript': 'Нижний индекс',
+		'Superscript': 'Верхний индекс',
+		'Align left': 'Выравнивание по левому краю',
+		'Center': 'Выравнивание по центру',
+		'Align right': 'Выравнивание по правому краю',
+		'Justify': 'Выравнивание по обоим краям',
+		'Font Name': 'Шрифт',
+		'Font Size': 'Размер шрифта',
+		'Font Color': 'Цвет шрифта',
+		'Remove Formatting': 'Удалить форматирование',
+		'Cut': 'Вырезать',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Ваш браузер не позволяет выполнять эту команду. Пожалуйста, используйте сочетание клавиш Ctrl / Cmd-X',
+		'Copy': 'Копировать',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Ваш браузер не позволяет выполнять эту команду. Пожалуйста, используйте сочетание клавиш Ctrl / Cmd-C',
+		'Paste': 'Выставить',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Ваш браузер не позволяет выполнять эту команду. Пожалуйста, используйте сочетание клавиш Ctrl / Cmd-V',
+		'Paste your text inside the following box:': 'Вставьте текст в следующее окно:',
+		'Paste Text': 'Вставить текст',
+		'Bullet list': 'Маркированный список',
+		'Numbered list': 'Нумерованный список',
+		'Undo': 'Отменить',
+		'Redo': 'Повторить',
+		'Rows:': 'Строки',
+		'Cols:': 'Столбцы',
+		'Insert a table': 'Таблица',
+		'Insert a horizontal rule': 'Горизонтальная линия',
+		'Code': 'Код',
+		'Insert a Quote': 'Цитата',
+		'Width (optional):': 'Ширина (необязательно):',
+		'Height (optional):': 'Высота (необязательно):',
+		'Insert an image': 'Изображение',
+		'E-mail:': 'E-mail',
+		'Insert an email': 'E-mail',
+		'URL:': 'URL:',
+		'Insert a link': 'Ссылка',
+		'Unlink': 'Удалить ссылку',
+		'More': 'Больше',
+		'Insert an emoticon': 'Смайлы',
+		'Video URL:': 'Видео URL',
+		'Insert': 'Вставить',
+		'Insert a YouTube video': 'YouTube-видео',
+		'Insert current date': 'Текущая дата',
+		'Insert current time': 'Текущее время',
+		'Print': 'Распечатать',
+		'View source': 'Показать код',
+		'Maximize': 'Развернуть',
+		'Left-to-Right': 'Слева направо',
+		'Right-to-Left': 'Справа налево',
+		'Description (optional):': 'Описание (необязательно):',
+		dateFormat: 'day.month.year'
+	};
+})();

+ 70 - 0
public/js/sc/languages/sk.js

@@ -0,0 +1,70 @@
+/**
+ * @author Kevo <me@kevo.link>
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+	sceditor.locale['sk'] = {
+		'Bold': 'Tučné',
+		'Italic': 'Kurzíva',
+		'Underline': 'Podčiarknuté',
+		'Strikethrough': 'Prečiarknuté',
+		'Subscript': 'Dolný index',
+		'Superscript': 'Horný index',
+		'Align left': 'Zarovnať vľavo',
+		'Center': 'Zarovnať na stred',
+		'Align right': 'Zarovnať vpravo',
+		'Justify': 'Zarovnať do bloku',
+		'Font Name': 'Typ písma',
+		'Font Size': 'Veľkosť písma',
+		'Font Color': 'Farba písma',
+		'Remove Formatting': 'Odstrániť formátovanie',
+		'Cut': 'Vystrihnúť',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Váš prehliadač nepodporuje príkaz pre vystrihnutie. Prosím, použite klávesovú skratku Ctrl/Cmd-X',
+		'Copy': '',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Váš prehliadač nepodporuje príkaz pre skopírovanie. Prosím, použite klávesovú skratku Ctrl/Cmd-C',
+		'Paste': '',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Váš prehliadač nepodporuje príkaz pre vloženie. Prosím, použite klávesovú skratku Ctrl/Cmd-V',
+		'Paste your text inside the following box:': 'Vložte Váš text do nasledujúceho poľa',
+		'Paste Text': 'Vložiť text',
+		'Bullet list': 'Zoznam',
+		'Numbered list': 'Číslovaný zoznam',
+		'Undo': 'Krok späť',
+		'Redo': 'Krok vpred',
+		'Rows:': 'Riadkov:',
+		'Cols:': 'Stĺpcov:',
+		'Insert a table': 'Vložiť tabuľku',
+		'Insert a horizontal rule': 'Vložiť vodorovnú čiaru',
+		'Code': 'Vložiť kód',
+		'Width (optional):': 'Šírka (voliteľné):',
+		'Height (optional):': 'Výška (voliteľné):',
+		'Insert an image': 'Vložiť obrázok',
+		'E-mail:': 'E-mail:',
+		'Insert an email': 'Vložiť E-mail',
+		'URL:': 'URL adresa:',
+		'Insert a link': 'Vložiť odkaz',
+		'Unlink': 'Zrušiť odkaz',
+		'More': 'Viac',
+		'Insert an emoticon': 'Vložiť smajlíka',
+		'Video URL:': 'URL adresa videa:',
+		'Insert': 'Vložiť',
+		'Insert a YouTube video': 'Vložiť YouTube video',
+		'Insert current date': 'Vložiť dnešný dátum',
+		'Insert current time': 'Vložiť aktuálny čas',
+		'Print': 'Vytlačiť',
+		'View source': 'Zobraziť zdrojový kód',
+		'Description (optional):': 'Popis (voliteľné):',
+		'Enter the image URL:': 'Vložte URL adresu obrázka:',
+		'Enter the e-mail address:': 'Vložte E-mailovú adresu:',
+		'Enter the displayed text:': 'Vložte zobrazovaný text:',
+		'Enter URL:': 'Vložte URL adresu:',
+		'Enter the YouTube video URL or ID:': 'Vložte URL adresu YouTube videa alebo jeho ID:',
+		'Insert a Quote': 'Vložiť citát',
+		'Invalid YouTube video': 'Neplatné YouTube video',
+		'Left-to-Right': 'Zľava doprava',
+		'Right-to-Left': 'Zprava doľava',
+		'Drop files here': 'Presuňte súbory sem',
+		'Maximize': 'Maximalizovať',
+		dateFormat: 'day. month. year'
+	};
+})();

+ 58 - 0
public/js/sc/languages/sv.js

@@ -0,0 +1,58 @@
+(function () {
+	'use strict';
+
+	sceditor.locale['sv-SE'] = {
+		'Bold': 'Fet',
+		'Italic': 'Kursiv',
+		'Underline': 'Understruken',
+		'Strikethrough': 'Genomstruken',
+		'Subscript': 'Nersänkt',
+		'Superscript': 'Upphöjt',
+		'Align left': 'Vänsterställ',
+		'Center': 'Centrera',
+		'Align right': 'Högerställ',
+		'Justify': 'Normalt oppstilt',
+		'Font Name': 'Teckensnitt',
+		'Font Size': 'Teckenstorlek',
+		'Font Color': 'Teckenfärg',
+		'Remove Formatting': 'Ta bort formatering',
+		'Cut': 'Klipp ut',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Din webbläsare kan inte utföra kommandot. Vänligen använd kortkommando Ctrl / Cmd-X',
+		'Copy': 'Kopiera',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Din webbläsare kan inte utföra kommandot. Vänligen använd kortkommando Ctrl / Cmd-C',
+		'Paste': 'Klista in',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Din webbläsare kan inte utföra kommandot. Vänligen använd kortkommando Ctrl / Cmd-V',
+		'Paste your text inside the following box:': 'Klistra in din text i rutan:',
+		'Paste Text': 'Klistra in text',
+		'Bullet list': 'Lista',
+		'Numbered list': 'Numrerad lista',
+		'Undo': 'Ångra',
+		'Redo': 'Gör om',
+		'Rows:': 'Rader',
+		'Cols:': 'Kolumner',
+		'Insert a table': 'Infoga tabell',
+		'Insert a horizontal rule': 'Infoga skiljestreck',
+		'Code': 'Kod',
+		'Width (optional):': 'Bredd (valfritt):',
+		'Height (optional):': 'Höjd (valfritt):',
+		'Insert an image': 'Infoga bild',
+		'E-mail:': 'E-post',
+		'Insert an email': 'Infoga e-post',
+		'URL:': 'URL:',
+		'Insert a link': 'Infoga länk',
+		'Unlink': 'Ta bort länk',
+		'More': 'Mer',
+		'Insert an emoticon': 'Infoga smiley',
+		'Video URL:': 'Video URL',
+		'Insert': 'Infoga',
+		'Insert a YouTube video': 'Infoga YouTube-video',
+		'Insert current date': 'Infoga dagens datum',
+		'Insert current time': 'Infoga nuvarande tid',
+		'Print': 'Skriv ut',
+		'View source': 'Visa källkod',
+		'Description (optional):': 'Beskrivning (valfritt):',
+		dateFormat: 'year-month-day'
+	};
+
+	sceditor.locale['sv'] = sceditor.locale['sv-SE'];
+})();

+ 80 - 0
public/js/sc/languages/template.js

@@ -0,0 +1,80 @@
+/**
+ * @author <Your Name> <Your e-mail/Website if you would like>
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	// Replace <code> with the language code, e.g. no, fr, en, ect.
+	sceditor.locale['<code>'] = {
+
+		// Original string is on the left, place the translation between
+		// the quotes on the right
+		'Bold': '',
+		'Italic': '',
+		'Underline': '',
+		'Strikethrough': '',
+		'Subscript': '',
+		'Superscript': '',
+		'Align left': '',
+		'Center': '',
+		'Align right': '',
+		'Justify': '',
+		'Font Name': '',
+		'Font Size': '',
+		'Font Color': '',
+		'Remove Formatting': '',
+		'Cut': '',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': '',
+		'Copy': '',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': '',
+		'Paste': '',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': '',
+		'Paste your text inside the following box:': '',
+		'Paste Text': '',
+		'Bullet list': '',
+		'Numbered list': '',
+		'Add indent': '',
+		'Remove one indent': '',
+		'Undo': '',
+		'Redo': '',
+		'Rows:': '',
+		'Cols:': '',
+		'Insert a table': '',
+		'Insert a horizontal rule': '',
+		'Code': '',
+		'Width (optional):': '',
+		'Height (optional):': '',
+		'Insert an image': '',
+		'E-mail:': '',
+		'Insert an email': '',
+		'URL:': '',
+		'Insert a link': '',
+		'Unlink': '',
+		'More': '',
+		'Insert an emoticon': '',
+		'Video URL:': '',
+		'Insert': '',
+		'Insert a YouTube video': '',
+		'Insert current date': '',
+		'Insert current time': '',
+		'Print': '',
+		'Maximize': '',
+		'View source': '',
+		'Description (optional):': '',
+		'Enter the image URL:': '',
+		'Enter the e-mail address:': '',
+		'Enter the displayed text:': '',
+		'Enter URL:': '',
+		'Enter the YouTube video URL or ID:': '',
+		'Insert a Quote': '',
+		'Invalid YouTube video': '',
+		'Drop files here': '',
+		'Left-to-Right': '',
+		'Right-to-Left': '',
+
+		// month format, replace - with the date format separator and order in the
+		// order used
+		dateFormat: 'day-month-year'
+	};
+})();

+ 66 - 0
public/js/sc/languages/tr.js

@@ -0,0 +1,66 @@
+/**
+ * @author Mahmut Yaman - iletisim@/m-yaman.com
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+	sceditor.locale['tr'] = {
+		'Bold': 'Kalın',
+		'Italic': 'İtalik',
+		'Underline': 'Altı çizgili',
+		'Strikethrough': 'Üstü çizgili',
+		'Subscript': 'Simge',
+		'Superscript': 'Üstsimge',
+		'Align left': 'Sola yasla',
+		'Center': 'Ortala',
+		'Align right': 'Sağa yasla',
+		'Justify': 'Satır uzunluğuna ayarla',
+		'Font Name': 'Yazı tipi',
+		'Font Size': 'Yazı boyutu',
+		'Font Color': 'Yazı rengi',
+		'Remove Formatting': 'Biçimlendirmeyi temizle',
+		'Cut': 'Kes',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Tarayıcınız kesme komutuna izin vermiyor. Lütfen Ctrl/Cmd-X klavye kısayolunu kullanın.',
+		'Copy': 'Kopyala',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Tarayıcınız kopyalama komutuna izin vermiyor. Lütfen Ctrl/Cmd-C klavye kısayolunu kullanın.',
+		'Paste': 'Yapıştır',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Tarayıcınız yapıştırma komutuna izin vermiyor. Lütfen Ctrl/Cmd-V klavye kısayolunu kullanın.',
+		'Paste your text inside the following box:': 'Yazınızı bu kutucuğa yapıştırın:',
+		'Paste Text': 'Metin Yapıştır',
+		'Bullet list': 'Madde işaretli liste',
+		'Numbered list': 'Numaralı liste',
+		'Undo': 'Geri al',
+		'Redo': 'Yinele',
+		'Rows:': 'Sütun:',
+		'Cols:': 'Kolon:',
+		'Insert a table': 'Tablo ekle',
+		'Insert a horizontal rule': 'Yatay ayraç ekle',
+		'Code': 'Kod',
+		'Width (optional):': 'Genişlik (opsiyonel):',
+		'Height (optional):': 'Yükseklik (opsiyonel):',
+		'Insert an image': 'Resim ekle',
+		'E-mail:': 'E-posta:',
+		'Insert an email': 'E-posta ekle',
+		'URL:': 'URL:',
+		'Insert a link': 'Bağlantı ekle',
+		'Unlink': 'Bağlantıyı kaldır',
+		'More': 'Daha fazla',
+		'Insert an emoticon': 'Yüz ifadesi ekle',
+		'Video URL:': 'Video URL:',
+		'Insert': 'Ekle',
+		'Insert a YouTube video': 'YouTube videosu ekle',
+		'Insert current date': 'Şuanki tarihi ekle',
+		'Insert current time': 'Şuanki saati ekle',
+		'Print': 'Yazdır',
+		'View source': 'Kaynağı görüntüle',
+		'Description (optional):': 'Açıklama (opsiyonel):',
+		'Enter the image URL:': 'Resim URL\'sini girin:',
+		'Enter the e-mail address:': 'E-posta adresini girin:',
+		'Enter the displayed text:': 'Görünecek yazıyı girin:',
+		'Enter URL:': 'URL\'yi girin:',
+		'Enter the YouTube video URL or ID:': 'YouTube video URL\'sini yada ID\'sini girin:',
+		'Insert a Quote': 'Alıntı ekle',
+		'Invalid YouTube video': 'Geçersiz YouTube videosu',
+		dateFormat: 'day-month-year'
+	};
+})();

+ 68 - 0
public/js/sc/languages/tw.js

@@ -0,0 +1,68 @@
+/**
+ * @author <Your Name> <Your e-mail/Website if you would like>
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['tw'] = {
+		'Bold': '粗體',
+		'Italic': '斜體',
+		'Underline': '底線',
+		'Strikethrough': '删除線',
+		'Subscript': '下標',
+		'Superscript': '上標',
+		'Align left': '靠左對齊',
+		'Center': '置中',
+		'Align right': '靠右對齊',
+		'Justify': '兩端對齊',
+		'Font Name': '字形',
+		'Font Size': '字體大小',
+		'Font Color': '文字顏色',
+		'Remove Formatting': '清除格式',
+		'Cut': '剪下',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': '您的瀏覽器不支持剪下命令,請使用快速键 Ctrl/Cmd-X',
+		'Copy': '拷貝',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': '您的瀏覽器不支持拷貝命令,請使用快速键 Ctrl/Cmd-C',
+		'Paste': '貼上',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': '您的瀏覽器不支持貼上命令,請使用快速键 Ctrl/Cmd-V',
+		'Paste your text inside the following box:': '請在下面貼上您的文字',
+		'Paste Text': '貼上纯文字',
+		'Bullet list': '符號列表',
+		'Numbered list': '编號列表',
+		'Undo': '復原',
+		'Redo': '重做',
+		'Rows:': '行數',
+		'Cols:': '列數',
+		'Insert a table': '插入表格',
+		'Insert a horizontal rule': '插入分隔線',
+		'Code': '原始碼',
+		'Width (optional):': '寬度(選填)',
+		'Height (optional):': '高度(選填)',
+		'Insert an image': '插入圖片',
+		'E-mail:': 'Email',
+		'Insert an email': '插入Email',
+		'URL:': '網址',
+		'Insert a link': '插入超鏈結',
+		'Unlink': '取消超鏈結',
+		'More': '更多',
+		'Insert an emoticon': '插入表情符號',
+		'Video URL:': '影片網址',
+		'Insert': '插入',
+		'Insert a YouTube video': '插入 YouTube 影片',
+		'Insert current date': '插入目前日期',
+		'Insert current time': '插入目前時間',
+		'Print': '列印',
+		'View source': '查看原始碼',
+		'Description (optional):': '描述(選填)',
+		'Enter the image URL:': '輸入圖片網址',
+		'Enter the e-mail address:': '輸入 Email',
+		'Enter the displayed text:': '輸入顯示文字',
+		'Enter URL:': '輸入網址',
+		'Enter the YouTube video URL or ID:': '輸入 YouTube 網址或影片编號',
+		'Insert a Quote': '插入引用',
+		'Invalid YouTube video': '無效的YouTube影片',
+
+		dateFormat: 'year-month-day'
+	};
+})();

+ 57 - 0
public/js/sc/languages/uk.js

@@ -0,0 +1,57 @@
+(function () {
+	'use strict';
+
+	sceditor.locale['uk'] = {
+		'Bold': 'Жирний',
+		'Italic': 'Курсив',
+		'Underline': 'Підкреслений',
+		'Strikethrough': 'Закреслений',
+		'Subscript': 'Нижній індекс',
+		'Superscript': 'Верхній індекс',
+		'Align left': 'Вирівняти по лівому краю',
+		'Center': 'Вирівняти по центру',
+		'Align right': 'Вирівняти по правому краю',
+		'Justify': 'Вирівняти по ширині',
+		'Font Name': 'Шрифт',
+		'Font Size': 'Розмір шрифту',
+		'Font Color': 'Колір шрифту',
+		'Remove Formatting': 'Видалити форматування',
+		'Cut': 'Вирізати',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Ваш браузер не дозволяє виконати цю команду. Будь ласка, використовуйте комбінацію клавіш Ctrl/Cmd-X',
+		'Copy': 'Копіювати',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Ваш браузер не дозволяє виконати цю команду. Будь ласка, використовуйте комбінацію клавіш Ctrl/Cmd-C',
+		'Paste': 'Вставити',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Ваш браузер не дозволяє виконати цю команду. Будь ласка, використовуйте комбінацію клавіш Ctrl/Cmd-V',
+		'Paste your text inside the following box:': 'Вставте текст у наступне вікно:',
+		'Paste Text': 'Вставити текст',
+		'Bullet list': 'Маркований список',
+		'Numbered list': 'Нумерований список',
+		'Undo': 'Відмінити',
+		'Redo': 'Повторити',
+		'Rows:': 'Рядків:',
+		'Cols:': 'Cтовпців:',
+		'Insert a table': 'Додати таблицю',
+		'Insert a horizontal rule': 'Додати горизонтальну лінію',
+		'Code': 'Код',
+		'Insert a Quote': 'Додати цитату',
+		'Width (optional):': 'Ширина (необов\'язково):',
+		'Height (optional):': 'Висота (необов\'язково):',
+		'Insert an image': 'Додати зображення',
+		'E-mail:': 'E-mail:',
+		'Insert an email': 'Додати E-mail',
+		'URL:': 'URL:',
+		'Insert a link': 'Додати посилання',
+		'Unlink': 'Видалити посилання',
+		'More': 'Більше',
+		'Insert an emoticon': 'Додати смайлик',
+		'Video URL:': 'URL відео:',
+		'Insert': 'Вставити',
+		'Insert a YouTube video': 'Додати відео з YouTube',
+		'Insert current date': 'Додати дату',
+		'Insert current time': 'Додати час',
+		'Print': 'Надрукувати',
+		'View source': 'Показати код',
+		'Maximize': 'Розгорнути редактор',
+		dateFormat: 'day.month.year'
+	};
+})();

+ 68 - 0
public/js/sc/languages/vi.js

@@ -0,0 +1,68 @@
+/**
+ * @author Chien
+ * @license [MIT](http://www.opensource.org/licenses/mit-license.php)
+ */
+(function () {
+	'use strict';
+
+	sceditor.locale['vi'] = {
+		'Bold': 'Đậm',
+		'Italic': 'Nghiêng',
+		'Underline': 'Gạch chân',
+		'Strikethrough': 'Gạch giữa',
+		'Subscript': 'Hệ số',
+		'Superscript': 'Mũ',
+		'Align left': 'Căn trái',
+		'Center': 'Căn giữa',
+		'Align right': 'Căn phải',
+		'Justify': 'Căn đều',
+		'Font Name': 'Phông chữ',
+		'Font Size': 'Cỡ chữ',
+		'Font Color': 'Màu chữ',
+		'Remove Formatting': 'Xóa định dạng',
+		'Cut': 'Cắt',
+		'Your browser does not allow the cut command. Please use the keyboard shortcut Ctrl/Cmd-X': 'Trình duyệt không cho phép sử dụng lệnh Cut. Vui lòng sử dụng phím tắt Ctrl/Cmd-X',
+		'Copy': 'Sao chép',
+		'Your browser does not allow the copy command. Please use the keyboard shortcut Ctrl/Cmd-C': 'Trình duyệt không cho phép sử dụng lệnh Copy. Vui lòng sử dụng phím tắt Ctrl/Cmd-C',
+		'Paste': 'Chép vào',
+		'Your browser does not allow the paste command. Please use the keyboard shortcut Ctrl/Cmd-V': 'Trình duyệt không cho phép sử dụng lệnh Paste. Vui lòng sử dụng phím tắt Ctrl/Cmd-V',
+		'Paste your text inside the following box:': 'Chép nội dung text vào khung sau',
+		'Paste Text': 'Chép nội dung text',
+		'Bullet list': 'Danh sách kiểu nốt',
+		'Numbered list': 'Danh sách kiểu số',
+		'Undo': 'Hủy bỏ',
+		'Redo': 'Trở lại bước trước',
+		'Rows:': 'Số dòng',
+		'Cols:': 'Số cột',
+		'Insert a table': 'Thêm bảng',
+		'Insert a horizontal rule': 'Thêm thước ngang',
+		'Code': 'Mã code',
+		'Width (optional):': 'Dài (không bắt buộc)',
+		'Height (optional):': 'Rộng (không bắt buộc)',
+		'Insert an image': 'Chèn hình ảnh',
+		'E-mail:': 'E-mail',
+		'Insert an email': 'Chèn email',
+		'URL:': 'Liên kết',
+		'Insert a link': 'Chèn liên kết',
+		'Unlink': 'Bỏ liên kết',
+		'More': 'Xem thêm',
+		'Insert an emoticon': 'Chèn biểu tượng',
+		'Video URL:': 'Đường dẫn của Video',
+		'Insert': 'Thêm vào',
+		'Insert a YouTube video': 'Chèn Youtube',
+		'Insert current date': 'Chèn ngày hiện tại',
+		'Insert current time': 'Chèn thời gian hiện tại',
+		'Print': 'In ấn',
+		'View source': 'Xem mã nguồn',
+		'Description (optional):': 'Mô tả (không bắt buộc)',
+		'Enter the image URL:': 'Nhập vào đường dẫn của hình ảnh',
+		'Enter the e-mail address:': 'Nhập vào địa chỉ email',
+		'Enter the displayed text:': 'Nhập vào nội dung hiển thị',
+		'Enter URL:': 'Nhập vào liên kết',
+		'Enter the YouTube video URL or ID:': 'Nhập vào liên kết của video hoặc ID trên Youtube',
+		'Insert a Quote': 'Chèn trích dẫn',
+		'Invalid YouTube video': 'Video Youtube không chính xác',
+
+		dateFormat: 'day/month/year'
+	};
+})();

+ 157 - 0
public/js/sc/plugins/alternative-lists.js

@@ -0,0 +1,157 @@
+/**
+ * SCEditor Inline-Code Plugin for BBCode format
+ * http://www.sceditor.com/
+ *
+ * Copyright (C) 2011-2013, Sam Clarke (samclarke.com)
+ *
+ * SCEditor is licensed under the MIT license:
+ *	http://www.opensource.org/licenses/mit-license.php
+ *
+ * @fileoverview SCEditor alternative lists plugin
+ * This plugin implements phpBB style of the lists:
+ * [list]
+ * [*]item
+ * [*]item
+ * [/list]
+ * @author Alex Betis
+ */
+
+(function (sceditor) {
+	'use strict';
+
+	var utils = sceditor.utils;
+
+	function isFunction(fn) {
+		return typeof fn === 'function';
+	}
+
+	sceditor.plugins['alternative-lists'] = function () {
+		var base = this;
+
+		/**
+		 * Private functions
+		 * @private
+		 */
+		var bulletHandler;
+		var orderedHandler;
+		var insertListTag;
+
+		base.init = function () {
+			var opts = this.opts;
+
+			// Enable for BBCode only
+			if (opts.format && opts.format !== 'bbcode') {
+				return;
+			}
+
+			// Override only txtExec implementation
+			sceditor.command.get('orderedlist').txtExec = orderedHandler;
+			sceditor.command.get('bulletlist').txtExec = bulletHandler;
+
+			// Override current implementation
+			sceditor.formats.bbcode.set('list', {
+				breakStart: true,
+				isInline: false,
+				skipLastLineBreak: true,
+				html: function (token, attrs, content) {
+					var listType = 'disc';
+					var toHtml = null;
+
+					if (attrs.defaultattr) {
+						listType = attrs.defaultattr;
+					}
+
+					if (listType === '1') {
+						// This listType belongs to orderedList (OL)
+						toHtml = sceditor.formats.bbcode.get('ol').html;
+					} else {
+						// unknown listType, use default bullet list behavior
+						toHtml = sceditor.formats.bbcode.get('ul').html;
+					}
+
+					if (isFunction(toHtml)) {
+						return toHtml.call(this, token, attrs, content);
+					} else {
+						token.attrs['0'] = content;
+						return sceditor.formats.bbcode.formatBBCodeString(
+							toHtml, token.attrs);
+					}
+				}
+			});
+
+			sceditor.formats.bbcode.set('ul', {
+				tags: {
+					ul: null
+				},
+				breakStart: true,
+				isInline: false,
+				skipLastLineBreak: true,
+				format: '[list]{0}[/list]',
+				html: '<ul>{0}</ul>'
+			});
+
+			sceditor.formats.bbcode.set('ol', {
+				tags: {
+					ol: null
+				},
+				breakStart: true,
+				isInline: false,
+				skipLastLineBreak: true,
+				format: '[list=1]{0}[/list]',
+				html: '<ol>{0}</ol>'
+			});
+
+			sceditor.formats.bbcode.set('li', {
+				tags: {
+					li: null
+				},
+				isInline: false,
+				closedBy: ['/ul', '/ol', '/list', '*', 'li'],
+				format: '[*]{0}',
+				html: '<li>{0}</li>'
+			});
+
+			sceditor.formats.bbcode.set('*', {
+				isInline: false,
+				excludeClosing: true,
+				closedBy: ['/ul', '/ol', '/list', '*', 'li'],
+				html: '<li>{0}</li>'
+			});
+		};
+
+		insertListTag = function (editor, listType, selected) {
+			var content = '';
+
+			utils.each(selected.split(/\r?\n/), function (item) {
+				content += (content ? '\n' : '') +
+					'[*]' + item;
+			});
+
+			if (listType === '') {
+				editor.insertText('[list]\n' + content + '\n[/list]');
+			} else {
+				editor.insertText('[list=' + listType + ']\n' + content +
+				'\n[/list]');
+			}
+		};
+
+		/**
+		 * Function for the txtExec and exec properties
+		 *
+		 * @param  {node} caller
+		 * @private
+		 */
+		orderedHandler = function (caller, selected) {
+			var editor = this;
+
+			insertListTag(editor, '1', selected);
+		};
+
+		bulletHandler = function (caller, selected) {
+			var editor = this;
+
+			insertListTag(editor, '', selected);
+		};
+
+	};
+})(sceditor);

Plik diff jest za duży
+ 4385 - 0
public/js/sc/sceditor.js


+ 98 - 0
public/js/scloader.js

@@ -0,0 +1,98 @@
+/**
+ * This file is part of the ForkBB <https://github.com/forkbb>.
+ *
+ * @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
+ * @license   The MIT License (MIT)
+ */
+
+if (typeof ForkBB === "undefined" || !ForkBB) {
+    var ForkBB = {};
+}
+
+ForkBB.editor = (function (doc, win) {
+    'use strict';
+
+    var instance,
+        dataName = "data-SCEditorConfig",
+        emotName = "data-smiliesEnabled",
+        linkName = "data-linkEnabled",
+        selector = "textarea[" + dataName + "]",
+        textarea,
+        options = {
+            format: 'bbcode',
+            icons: 'monocons',
+            style: '',
+            emoticonsCompat: true,
+            emoticonsEnabled: false,
+            resizeWidth: false,
+            width: '100%',
+            toolbar: 'bold,italic,underline,strike,subscript,superscript|' +
+                'left,center,right,justify|font,size,color,removeformat|' +
+                'bulletlist,orderedlist,indent,outdent|' +
+                'table|code,quote|horizontalrule,image,email,link,unlink|' +
+                'emoticon,date,time|maximize,source',
+            colors: '#000000,#808080,#C0C0C0,#FFFFFF|#FF00FF,#800080,#FF0000,#800000|#FFFF00,#808000,#00FF00,#008000|#00FFFF,#008080,#0000FF,#000080'
+        };
+
+    function initEditor()
+    {
+        var conf, smiliesEnabled, linkEnabled;
+
+        if (
+            !sceditor
+            || !(textarea = doc.querySelector(selector))
+            || !(conf = JSON.parse(textarea.getAttribute(dataName)))
+        ) {
+            return;
+        }
+
+        options = Object.assign(options, conf);
+        smiliesEnabled = '1' == textarea.getAttribute(emotName);
+        linkEnabled = '1' == textarea.getAttribute(linkName);
+
+        if (!smiliesEnabled) {
+            options.toolbar = options.toolbar.replace(/\bemoticon\b/, '');
+        }
+        if (!linkEnabled) {
+            options.toolbar = options.toolbar.replace(/\b(image|email|link)\b/g, '');
+        }
+        options.toolbar = options.toolbar.replace(/[^\w]*\|[^\w]*/g, '|').replace(/,{2,}/g, ',');
+
+        sceditor.create(textarea, options);
+        instance = sceditor.instance(textarea);
+
+        var forDelete = ['youtube', /*'rtl', 'ltr'*/];
+
+        if (!linkEnabled) {
+            forDelete = forDelete.concat('url', /*'img',*/ 'email');
+        }
+
+        for (var bbcodeForDelete of forDelete) {
+            sceditor.command.remove(bbcodeForDelete);
+            sceditor.formats.bbcode.remove(bbcodeForDelete);
+        }
+
+        if (smiliesEnabled) {
+            var checkbox = doc.querySelector('input[name="hide_smilies"]');
+
+            if (checkbox) {
+                checkbox.addEventListener('change', function (e) {
+                    instance.emoticons(!e.target.checked);
+                });
+                instance.emoticons(!checkbox.checked);
+            } else {
+                instance.emoticons(true);
+            }
+        }
+    }
+
+    return {
+        init : function () {
+            initEditor();
+        },
+    };
+}(document, window));
+
+if (document.addEventListener && Object.assign) {
+    document.addEventListener("DOMContentLoaded", ForkBB.editor.init, false);
+}

+ 187 - 0
public/style/ForkBB/sccontent.css

@@ -0,0 +1,187 @@
+html,
+body,
+a,
+abbr,
+acronym,
+address,
+applet,
+article,
+aside,
+audio,
+big,
+blockquote,
+canvas,
+caption,
+center,
+cite,
+code,
+dd,
+del,
+details,
+dfn,
+div,
+dl,
+dt,
+em,
+embed,
+fieldset,
+figcaption,
+figure,
+footer,
+form,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+header,
+hgroup,
+iframe,
+img,
+input,
+ins,
+kbd,
+label,
+legend,
+li,
+main,
+mark,
+menu,
+nav,
+object,
+ol,
+output,
+p,
+pre,
+q,
+ruby,
+samp,
+section,
+span,
+strike,
+sub,
+summary,
+sup,
+table,
+tbody,
+td,
+textarea,
+tfoot,
+th,
+thead,
+time,
+tr,
+tt,
+ul,
+var,
+video {
+  margin: 0;
+  padding: 0;
+  border: 0;
+  font: inherit;
+  box-sizing: border-box;
+  overflow-wrap: break-word;
+  word-break: break-word;
+}
+
+body {
+  color: #333333;
+  background-color: #FFFFFF;
+  font-family: Arial, Helvetica, sans-serif;
+  font-size: 1rem;
+  line-height: 1.5;
+}
+
+html {
+  height: 100%;
+}
+
+.ios {
+  /* Needed for iOS scrolling bug fix */
+  overflow: auto;
+  -webkit-overflow-scrolling: touch;
+}
+
+.ios body {
+  /* Needed for iOS scrolling bug fix */
+  position: relative;
+  overflow: auto;
+}
+
+body {
+  /* Needed to make sure body covers the whole editor and that
+    long lines don't cause horizontal scrolling */
+  min-height: 100%;
+  word-wrap: break-word;
+}
+
+body.placeholder::before {
+  content: attr(placeholder);
+  color: #555;
+  font-style: italic;
+}
+
+ol {
+  list-style-type: decimal;
+  list-style-position: outside;
+  padding-inline-start: 1.5rem;
+}
+
+ul {
+  list-style-type: disc;
+  list-style-position: outside;
+  padding-inline-start: 1.5rem;
+}
+
+code {
+  display: block;
+  white-space: pre;
+  margin: 0 0.625rem;
+  padding: 0.625rem;
+  background-color: #f7f7f7;
+  border: 0.0625rem solid #C0C0C0;
+  overflow: auto;
+  max-height: 45rem;
+  min-height: 2rem;
+  font-family: "DejaVu Sans Mono", Consolas, "Droid Sans Mono", Monospace, Monaco, "Courier New", Courier;
+}
+
+blockquote {
+  border-inline-start: 0.1875rem solid #AA7939;
+  border-top: 0.0625rem solid #AA7939;
+  padding: 0.625rem;
+}
+
+blockquote cite {
+  display: block;
+  padding: 0.625rem;
+  background-color: #F8F4E3 /*#D3B58D*/;
+  margin: -0.625rem -0.625rem 0 -0.625rem;
+}
+
+a {
+  color: #583200;
+  cursor: pointer;
+  text-decoration: none;
+}
+
+a:hover, a:focus {
+  background-color: #D3B58D;
+}
+
+table {
+  border-collapse: collapse;
+  border: 0.0625rem solid #333333;
+}
+
+td, th {
+  border: 0.0625rem solid #333333;
+  empty-cells: show;
+  padding: 0.3125rem;
+  min-width: 1rem;
+}
+
+th {
+  background-color: #D3B58D;
+}

+ 240 - 66
public/style/ForkBB/style.css

@@ -1515,7 +1515,82 @@ body,
   color: #D8000C;
 }
 
-/*********************/
+@media screen and (max-width: 49.9999rem) {
+  #fork .f-user-info > li:not(.f-username),
+  #fork .f-user-info-add > li {
+    display: inline-block;
+  }
+
+  #fork .f-user-info > li:not(.f-username) + li::before,
+  #fork .f-user-info-add > li + li::before {
+    display: inline-block;
+    content: "\2022";
+    padding-inline-end: 0.3125rem;
+  }
+}
+
+@media screen and (min-width: 50rem) {
+  #fork .f-post {
+    display: flex;
+    flex-wrap: wrap;
+  }
+
+  #fork .f-post-header {
+    width: 100%;
+  }
+
+  #fork .f-post-user {
+    width: 13rem;
+    border-inline-end: 0.0625rem solid #AA7939;
+    border-bottom: 0;
+  }
+
+  #fork .f-post-usticky {
+    flex-direction: column;
+    position: sticky;
+    top: 0.625rem;
+  }
+
+  #fork .f-user-info-first {
+    display: block;
+    margin-bottom: 0.625rem;
+    width: 100%;
+  }
+
+  #fork .f-user-info .f-username {
+    display: none;
+  }
+
+  #fork .f-avatar {
+    flex-grow: 0;
+    order: 0;
+    text-align: center;
+  }
+
+  #fork .f-user-info {
+    flex-grow: 0;
+    width: 100%;
+  }
+
+  #fork .f-post-body {
+    width: calc(100% - 13rem);
+    position: relative;
+    display: flex;
+    flex-direction: column;
+  }
+
+  #fork .f-post-main {
+    flex-grow: 1;
+  }
+
+  #fork .f-avatar > img {
+    max-width: 100%;
+  }
+} /* @media screen and (min-width: 50rem) */
+
+/**********/
+/* bbcode */
+/**********/
 #fork .f-bb-header {
   font-weight: bold;
   font-size: 1.25rem;
@@ -1543,11 +1618,13 @@ body,
 }
 
 #fork .f-bb-code {
-  border: 0.0625rem solid #AA7939;
+  margin: 0 0.625rem;
   padding: 0.625rem;
-  background-color: #F8F4E3 /*#D3B58D*/;
+  background-color: #f7f7f7;
+  border: 0.0625rem solid #C0C0C0;
   overflow: auto;
   max-height: 45rem;
+  min-height: 2rem;
 }
 
 #fork .f-bb-l-disc {
@@ -1583,78 +1660,179 @@ body,
   background-color: #FFBABA;
 }
 
-@media screen and (max-width: 49.9999rem) {
-  #fork .f-user-info > li:not(.f-username),
-  #fork .f-user-info-add > li {
-    display: inline-block;
-  }
+#fork .f-bb-left {
+  text-align: left;
+}
 
-  #fork .f-user-info > li:not(.f-username) + li::before,
-  #fork .f-user-info-add > li + li::before {
-    display: inline-block;
-    content: "\2022";
-    padding-inline-end: 0.3125rem;
-  }
+#fork .f-bb-right {
+  text-align: right;
 }
 
-@media screen and (min-width: 50rem) {
-  #fork .f-post {
-    display: flex;
-    flex-wrap: wrap;
-  }
+#fork .f-bb-center {
+  text-align: center;
+}
 
-  #fork .f-post-header {
-    width: 100%;
-  }
+#fork .f-bb-justify {
+  text-align: justify;
+}
 
-  #fork .f-post-user {
-    width: 13rem;
-    border-inline-end: 0.0625rem solid #AA7939;
-    border-bottom: 0;
-  }
+#fork .f-bb-u {
+  text-decoration: underline;
+}
 
-  #fork .f-post-usticky {
-    flex-direction: column;
-    position: sticky;
-    top: 0.625rem;
-  }
+#fork .f-bb-table {
+  border-collapse: collapse;
+  border: 0.0625rem solid #333333;
+}
 
-  #fork .f-user-info-first {
-    display: block;
-    margin-bottom: 0.625rem;
-    width: 100%;
-  }
+#fork .f-bb-td,
+#fork .f-bb-th {
+  border: 0.0625rem solid #333333;
+  empty-cells: show;
+  padding: 0.3125rem;
+  min-width: 1rem;
+}
 
-  #fork .f-user-info .f-username {
-    display: none;
-  }
+#fork .f-bb-th {
+  background-color: #D3B58D;
+}
 
-  #fork .f-avatar {
-    flex-grow: 0;
-    order: 0;
-    text-align: center;
-  }
+#fork .f-bb-size1 {
+  font-size: xx-small;
+}
 
-  #fork .f-user-info {
-    flex-grow: 0;
-    width: 100%;
-  }
+#fork .f-bb-size2 {
+  font-size: small;
+}
 
-  #fork .f-post-body {
-    width: calc(100% - 13rem);
-    position: relative;
-    display: flex;
-    flex-direction: column;
-  }
+#fork .f-bb-size3 {
+  font-size: medium;
+}
 
-  #fork .f-post-main {
-    flex-grow: 1;
-  }
+#fork .f-bb-size4 {
+  font-size: large;
+}
 
-  #fork .f-avatar > img {
-    max-width: 100%;
-  }
-} /* @media screen and (min-width: 50rem) */
+#fork .f-bb-size5 {
+  font-size: x-large;
+}
+
+#fork .f-bb-size6 {
+  font-size: xx-large;
+}
+
+#fork .f-bb-size7 {
+  font-size: 3rem;
+  font-size: xxx-large; /* https://caniuse.com/mdn-css_properties_font-size_xxx-large */
+}
+
+#fork .f-bb-font[data-bb="Arial"] {
+  font-family: Arial;
+}
+
+#fork .f-bb-font[data-bb="Arial Black"] {
+  font-family: 'Arial Black';
+}
+
+#fork .f-bb-font[data-bb="Comic Sans MS"] {
+  font-family: 'Comic Sans MS';
+}
+
+#fork .f-bb-font[data-bb="Courier New"] {
+  font-family: 'Courier New';
+}
+
+#fork .f-bb-font[data-bb="Georgia"] {
+  font-family: Georgia;
+}
+
+#fork .f-bb-font[data-bb="Impact"] {
+  font-family: Impact;
+}
+
+#fork .f-bb-font[data-bb="Sans-serif"] {
+  font-family: Sans-serif;
+}
+
+#fork .f-bb-font[data-bb="Serif"] {
+  font-family: Serif;
+}
+
+#fork .f-bb-font[data-bb="Times New Roman"] {
+  font-family: 'Times New Roman';
+}
+
+#fork .f-bb-font[data-bb="Trebuchet MS"] {
+  font-family: 'Trebuchet MS';
+}
+
+#fork .f-bb-font[data-bb="Verdana"] {
+  font-family: Verdana;
+}
+
+#fork .f-bb-color[data-bb="#000000"] {
+  color: #000000;
+}
+
+#fork .f-bb-color[data-bb="#808080"] {
+  color: #808080;
+}
+
+#fork .f-bb-color[data-bb="#C0C0C0"] {
+  color: #C0C0C0;
+}
+
+#fork .f-bb-color[data-bb="#FFFFFF"] {
+  color: #FFFFFF;
+}
+
+#fork .f-bb-color[data-bb="#FF00FF"] {
+  color: #FF00FF;
+}
+
+#fork .f-bb-color[data-bb="#800080"] {
+  color: #800080;
+}
+
+#fork .f-bb-color[data-bb="#FF0000"] {
+  color: #FF0000;
+}
+
+#fork .f-bb-color[data-bb="#800000"] {
+  color: #800000;
+}
+
+#fork .f-bb-color[data-bb="#FFFF00"] {
+  color: #FFFF00;
+}
+
+#fork .f-bb-color[data-bb="#808000"] {
+  color: #808000;
+}
+
+#fork .f-bb-color[data-bb="#00FF00"] {
+  color: #00FF00;
+}
+
+#fork .f-bb-color[data-bb="#008000"] {
+  color: #008000;
+}
+
+#fork .f-bb-color[data-bb="#00FFFF"] {
+  color: #00FFFF;
+}
+
+#fork .f-bb-color[data-bb="#008080"] {
+  color: #008080;
+}
+
+#fork .f-bb-color[data-bb="#0000FF"] {
+  color: #0000FF;
+}
+
+#fork .f-bb-color[data-bb="#000080"] {
+  color: #000080;
+}
 
 /****************/
 /* Предпросмотр */
@@ -1918,10 +2096,6 @@ body,
 #fork .width98 {width: 98%;}
 #fork .width99 {width: 99%;}
 #fork .width100 {width: 100%;}
-#fork .text-align-left {text-align: left;}
-#fork .text-align-right {text-align: right;}
-#fork .text-align-center {text-align: center;}
-#fork .text-align-justify {text-align: justify;}
 
 /**********/
 /* Репорт */

+ 22 - 0
public/style/sc/LICENSE.md

@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (C) 2011-2016 by Sam Clarke and contributors
+http://www.sceditor.com/
+
+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.

+ 85 - 0
public/style/sc/themes/content/default.css

@@ -0,0 +1,85 @@
+/*! SCEditor | (C) 2011-2013, Sam Clarke | sceditor.com/license */
+html, body, p, code:before, table {
+	margin: 0;
+	padding: 0;
+	font-family: Verdana, Arial, Helvetica, sans-serif;
+	font-size: 14px;
+	color: #111;
+	line-height: 1.25;
+	overflow: visible;
+}
+html {
+	height: 100%;
+}
+.ios {
+	/* Needed for iOS scrolling bug fix */
+	overflow: auto;
+	-webkit-overflow-scrolling: touch;
+}
+.ios body {
+	/* Needed for iOS scrolling bug fix */
+	position: relative;
+	overflow: auto;
+}
+body {
+	/* Needed to make sure body covers the whole editor and that
+		long lines don't cause horizontal scrolling */
+	min-height: 100%;
+	word-wrap: break-word;
+}
+
+body.placeholder::before {
+    content: attr(placeholder);
+    color: #555;
+    font-style: italic;
+}
+
+ul, ol {
+	margin-top: 0;
+	margin-bottom: 0;
+	padding-top: 0;
+	padding-bottom: 0;
+}
+
+table, td {
+	border: 1px dotted #000;
+	empty-cells: show;
+}
+
+table td {
+	min-width: 5px;
+}
+
+code {
+	display: block;
+	background: #f1f1f1;
+	white-space: pre;
+	padding: 1em;
+	text-align: left;
+	margin: .25em 0;
+	direction: ltr;
+}
+
+blockquote {
+	background: #fff7d9;
+	margin: .25em 0;
+	border-left: .3em solid #f4e59f;
+	padding: .5em .5em .5em .75em;
+}
+blockquote cite {
+	font-weight: bold;
+	display: block;
+	font-size: 1em;
+	margin: 0 -.5em .25em -.75em;
+	padding: 0 .5em .15em .75em;
+	border-bottom: 1px solid #f4e59f;
+}
+
+h1, h2, h3, h4, h5, h6 {
+	padding: 0; margin: 0;
+}
+
+/* Prevent empty paragraphs from collapsing */
+div, p {
+	min-height: 1.25em;
+}

+ 595 - 0
public/style/sc/themes/default.css

@@ -0,0 +1,595 @@
+/*! SCEditor | (C) 2011-2016, Sam Clarke | sceditor.com/license */
+/**
+ * Default SCEditor
+ * http://www.sceditor.com/
+ *
+ * Copyright (C) 2011-16, Sam Clarke
+ *
+ * SCEditor is licensed under the MIT license:
+ *	http://www.opensource.org/licenses/mit-license.php
+ */
+#fork div.sceditor-grip,
+#fork .sceditor-button div {
+  background-image: url("famfamfam.png");
+  background-repeat: no-repeat;
+  width: 16px;
+  height: 16px;
+}
+#fork .sceditor-button-youtube div {
+  background-position: 0px 0px;
+}
+#fork .sceditor-button-link div {
+  background-position: 0px -16px;
+}
+#fork .sceditor-button-unlink div {
+  background-position: 0px -32px;
+}
+#fork .sceditor-button-underline div {
+  background-position: 0px -48px;
+}
+#fork .sceditor-button-time div {
+  background-position: 0px -64px;
+}
+#fork .sceditor-button-table div {
+  background-position: 0px -80px;
+}
+#fork .sceditor-button-superscript div {
+  background-position: 0px -96px;
+}
+#fork .sceditor-button-subscript div {
+  background-position: 0px -112px;
+}
+#fork .sceditor-button-strike div {
+  background-position: 0px -128px;
+}
+#fork .sceditor-button-source div {
+  background-position: 0px -144px;
+}
+#fork .sceditor-button-size div {
+  background-position: 0px -160px;
+}
+#fork .sceditor-button-rtl div {
+  background-position: 0px -176px;
+}
+#fork .sceditor-button-right div {
+  background-position: 0px -192px;
+}
+#fork .sceditor-button-removeformat div {
+  background-position: 0px -208px;
+}
+#fork .sceditor-button-quote div {
+  background-position: 0px -224px;
+}
+#fork .sceditor-button-print div {
+  background-position: 0px -240px;
+}
+#fork .sceditor-button-pastetext div {
+  background-position: 0px -256px;
+}
+#fork .sceditor-button-paste div {
+  background-position: 0px -272px;
+}
+#fork .sceditor-button-outdent div {
+  background-position: 0px -288px;
+}
+#fork .sceditor-button-orderedlist div {
+  background-position: 0px -304px;
+}
+#fork .sceditor-button-maximize div {
+  background-position: 0px -320px;
+}
+#fork .sceditor-button-ltr div {
+  background-position: 0px -336px;
+}
+#fork .sceditor-button-left div {
+  background-position: 0px -352px;
+}
+#fork .sceditor-button-justify div {
+  background-position: 0px -368px;
+}
+#fork .sceditor-button-italic div {
+  background-position: 0px -384px;
+}
+#fork .sceditor-button-indent div {
+  background-position: 0px -400px;
+}
+#fork .sceditor-button-image div {
+  background-position: 0px -416px;
+}
+#fork .sceditor-button-horizontalrule div {
+  background-position: 0px -432px;
+}
+#fork .sceditor-button-format div {
+  background-position: 0px -448px;
+}
+#fork .sceditor-button-font div {
+  background-position: 0px -464px;
+}
+#fork .sceditor-button-emoticon div {
+  background-position: 0px -480px;
+}
+#fork .sceditor-button-email div {
+  background-position: 0px -496px;
+}
+#fork .sceditor-button-date div {
+  background-position: 0px -512px;
+}
+#fork .sceditor-button-cut div {
+  background-position: 0px -528px;
+}
+#fork .sceditor-button-copy div {
+  background-position: 0px -544px;
+}
+#fork .sceditor-button-color div {
+  background-position: 0px -560px;
+}
+#fork .sceditor-button-code div {
+  background-position: 0px -576px;
+}
+#fork .sceditor-button-center div {
+  background-position: 0px -592px;
+}
+#fork .sceditor-button-bulletlist div {
+  background-position: 0px -608px;
+}
+#fork .sceditor-button-bold div {
+  background-position: 0px -624px;
+}
+#fork div.sceditor-grip {
+  background-position: 0px -640px;
+  width: 10px;
+  height: 10px;
+}
+#fork .rtl div.sceditor-grip {
+  background-position: 0px -650px;
+}
+/**
+ * SCEditor
+ * http://www.sceditor.com/
+ *
+ * Copyright (C) 2017, Sam Clarke (samclarke.com)
+ *
+ * SCEditor is licensed under the MIT license:
+ *	http://www.opensource.org/licenses/mit-license.php
+ */
+/*---------------------------------------------------
+    LESS Elements 0.7
+  ---------------------------------------------------
+    A set of useful LESS mixins
+    More info at: http://lesselements.com
+  ---------------------------------------------------*/
+ #fork .sceditor-container {
+  display: -ms-flexbox;
+  display: flex;
+  -ms-flex-direction: column;
+  flex-direction: column;
+  position: relative;
+  background: #fff;
+  border: 1px solid #d9d9d9;
+  font-size: 13px;
+  font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
+  color: #333;
+  line-height: 1;
+  font-weight: bold;
+  height: 250px;
+  border-radius: 4px;
+  background-clip: padding-box;
+}
+#fork .sceditor-container *,
+#fork .sceditor-container *:before,
+#fork .sceditor-container *:after {
+  -webkit-box-sizing: content-box;
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+#fork .sceditor-container,
+#fork .sceditor-container div,
+#fork div.sceditor-dropdown,
+#fork div.sceditor-dropdown div {
+  padding: 0;
+  margin: 0;
+  z-index: 3;
+}
+#fork .sceditor-container iframe,
+#fork .sceditor-container textarea {
+  display: block;
+  -ms-flex: 1 1 0%;
+  flex: 1 1 0%;
+  line-height: 1.25;
+  border: 0;
+  outline: none;
+  font-family: Verdana, Arial, Helvetica, sans-serif;
+  font-size: 14px;
+  color: #111;
+  padding: 0;
+  margin: 5px;
+  resize: none;
+  background: #fff;
+  height: auto !important;
+  width: auto !important;
+  width: calc(100% - 10px) !important;
+  min-height: 1px;
+}
+#fork .sceditor-container textarea {
+  margin: 7px 5px;
+}
+#fork div.sceditor-dnd-cover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+  background: rgba(255, 255, 255, 0.2);
+  border: 5px dashed #aaa;
+  z-index: 200;
+  font-size: 2em;
+  text-align: center;
+  color: #aaa;
+}
+#fork div.sceditor-dnd-cover p {
+  position: relative;
+  top: 45%;
+  pointer-events: none;
+}
+#fork div.sceditor-resize-cover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  background: #000;
+  width: 100%;
+  height: 100%;
+  z-index: 10;
+  opacity: 0.3;
+}
+#fork div.sceditor-grip {
+  overflow: hidden;
+  width: 10px;
+  height: 10px;
+  cursor: pointer;
+  position: absolute;
+  bottom: 0;
+  right: 0;
+  z-index: 3;
+  line-height: 0;
+}
+#fork div.sceditor-grip.has-icon {
+  background-image: none;
+}
+#fork .sceditor-maximize {
+  position: fixed;
+  top: 0;
+  left: 0;
+  height: 100% !important;
+  width: 100% !important;
+  border-radius: 0;
+  background-clip: padding-box;
+  z-index: 2000;
+}
+html.sceditor-maximize,
+body.sceditor-maximize {
+  height: 100%;
+  width: 100%;
+  padding: 0;
+  margin: 0;
+  overflow: hidden;
+}
+#fork .sceditor-maximize div.sceditor-grip {
+  display: none;
+}
+#fork .sceditor-maximize div.sceditor-toolbar {
+  border-radius: 0;
+  background-clip: padding-box;
+}
+/**
+	 * Dropdown styleing
+	 */
+   #fork div.sceditor-dropdown {
+  position: absolute;
+  border: 1px solid #ccc;
+  background: #fff;
+  z-index: 4000;
+  padding: 10px;
+  font-weight: normal;
+  font-size: 15px;
+  border-radius: 2px;
+  background-clip: padding-box;
+  box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.2);
+}
+#fork div.sceditor-dropdown *,
+#fork div.sceditor-dropdown *:before,
+#fork div.sceditor-dropdown *:after {
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+#fork div.sceditor-dropdown a,
+#fork div.sceditor-dropdown a:link {
+  color: #333;
+}
+#fork div.sceditor-dropdown form {
+  margin: 0;
+}
+#fork div.sceditor-dropdown label {
+  display: block;
+  font-weight: bold;
+  color: #3c3c3c;
+  padding: 4px 0;
+}
+#fork div.sceditor-dropdown input,
+#fork div.sceditor-dropdown textarea {
+  font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
+  outline: 0;
+  padding: 4px;
+  border: 1px solid #ccc;
+  border-top-color: #888;
+  margin: 0 0 0.75em;
+  border-radius: 1px;
+  background-clip: padding-box;
+}
+#fork div.sceditor-dropdown textarea {
+  padding: 6px;
+}
+#fork div.sceditor-dropdown input:focus,
+#fork div.sceditor-dropdown textarea:focus {
+  border-color: #aaa;
+  border-top-color: #666;
+  box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.1);
+}
+#fork div.sceditor-dropdown .button {
+  font-weight: bold;
+  color: #444;
+  padding: 6px 12px;
+  background: #ececec;
+  border: solid 1px #ccc;
+  border-radius: 2px;
+  background-clip: padding-box;
+  cursor: pointer;
+  margin: 0.3em 0 0;
+}
+#fork div.sceditor-dropdown .button:hover {
+  background: #f3f3f3;
+  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);
+}
+#fork div.sceditor-font-picker,
+#fork div.sceditor-fontsize-picker,
+#fork div.sceditor-format {
+  padding: 6px 0;
+}
+#fork div.sceditor-color-picker {
+  padding: 4px;
+}
+#fork div.sceditor-emoticons,
+#fork div.sceditor-more-emoticons {
+  padding: 0;
+}
+#fork .sceditor-pastetext textarea {
+  border: 1px solid #bbb;
+  width: 20em;
+}
+#fork .sceditor-emoticons img,
+#fork .sceditor-more-emoticons img {
+  padding: 0;
+  cursor: pointer;
+  margin: 2px;
+}
+#fork .sceditor-more {
+  border-top: 1px solid #bbb;
+  display: block;
+  text-align: center;
+  cursor: pointer;
+  font-weight: bold;
+  padding: 6px 0;
+}
+#fork .sceditor-dropdown a:hover {
+  background: #eee;
+}
+#fork .sceditor-fontsize-option,
+#fork .sceditor-font-option,
+#fork .sceditor-format a {
+  display: block;
+  padding: 7px 10px;
+  cursor: pointer;
+  text-decoration: none;
+  color: #222;
+}
+#fork .sceditor-fontsize-option {
+  padding: 7px 13px;
+}
+#fork .sceditor-color-column {
+  float: left;
+}
+#fork .sceditor-color-option {
+  display: block;
+  border: 2px solid #fff;
+  height: 18px;
+  width: 18px;
+  overflow: hidden;
+}
+#fork .sceditor-color-option:hover {
+  border: 1px solid #aaa;
+}
+/**
+	 * Toolbar styleing
+	 */
+#fork div.sceditor-toolbar {
+  flex-shrink: 0;
+  overflow: hidden;
+  padding: 3px 5px 2px;
+  background: #f7f7f7;
+  border-bottom: 1px solid #c0c0c0;
+  line-height: 0;
+  text-align: left;
+  user-select: none;
+  border-radius: 3px 3px 0 0;
+  background-clip: padding-box;
+}
+#fork div.sceditor-group {
+  display: inline-block;
+  background: #ddd;
+  margin: 1px 5px 1px 0;
+  padding: 1px;
+  border-bottom: 1px solid #aaa;
+  border-radius: 3px;
+  background-clip: padding-box;
+}
+#fork .sceditor-button {
+  float: left;
+  cursor: pointer;
+  padding: 3px 5px;
+  width: 16px;
+  height: 20px;
+  border-radius: 3px;
+  background-clip: padding-box;
+}
+#fork .sceditor-button:hover,
+#fork .sceditor-button:active,
+#fork .sceditor-button.active {
+  background: #fff;
+  box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2);
+}
+#fork .sceditor-button:active {
+  background: #fff;
+  box-shadow: inset 1px 1px 0 rgba(0,0,0,0.3), inset -1px 0 rgba(0,0,0,0.3), inset 0 -1px 0 rgba(0,0,0,0.2), inset 0 0 8px rgba(0,0,0,0.3);
+}
+#fork .sceditor-button.disabled:hover {
+  background: inherit;
+  cursor: default;
+  box-shadow: none;
+}
+#fork .sceditor-button,
+#fork .sceditor-button div {
+  display: block;
+}
+#fork .sceditor-button svg {
+  display: inline-block;
+  height: 16px;
+  width: 16px;
+  margin: 2px 0;
+  fill: #111;
+  text-decoration: none;
+  pointer-events: none;
+  line-height: 1;
+}
+#fork .sceditor-button.disabled svg {
+  fill: #888;
+}
+#fork .sceditor-button div {
+  display: inline-block;
+  margin: 2px 0;
+  padding: 0;
+  overflow: hidden;
+  line-height: 0;
+  font-size: 0;
+  color: transparent;
+}
+#fork .sceditor-button.has-icon div {
+  display: none;
+}
+#fork .sceditor-button.disabled div {
+  opacity: 0.3;
+}
+#fork .text .sceditor-button,
+#fork .text .sceditor-button div,
+#fork .sceditor-button.text,
+#fork .sceditor-button.text div,
+#fork .text-icon .sceditor-button,
+#fork .text-icon .sceditor-button div,
+#fork .sceditor-button.text-icon,
+#fork .sceditor-button.text-icon div {
+  display: inline-block;
+  width: auto;
+  line-height: 16px;
+  font-size: 1em;
+  color: inherit;
+  text-indent: 0;
+}
+#fork .text-icon .sceditor-button.has-icon div,
+#fork .sceditor-button.has-icon div,
+#fork .text .sceditor-button div,
+#fork .sceditor-button.text div {
+  padding: 0 2px;
+  background: none;
+}
+#fork .text .sceditor-button svg,
+#fork .sceditor-button.text svg {
+  display: none;
+}
+#fork .text-icon .sceditor-button div,
+#fork .sceditor-button.text-icon div {
+  padding: 0 2px 0 20px;
+}
+#fork .rtl div.sceditor-toolbar {
+  text-align: right;
+}
+#fork .rtl .sceditor-button {
+  float: right;
+}
+#fork .rtl div.sceditor-grip {
+  right: auto;
+  left: 0;
+}
+
+/* forkbb */
+.sceditor-color-option[data-color="#000000"] {
+  background-color: #000000;
+}
+
+.sceditor-color-option[data-color="#808080"] {
+  background-color: #808080;
+}
+
+.sceditor-color-option[data-color="#C0C0C0"] {
+  background-color: #C0C0C0;
+}
+
+.sceditor-color-option[data-color="#FFFFFF"] {
+  background-color: #FFFFFF;
+}
+
+.sceditor-color-option[data-color="#FF00FF"] {
+  background-color: #FF00FF;
+}
+
+.sceditor-color-option[data-color="#800080"] {
+  background-color: #800080;
+}
+
+.sceditor-color-option[data-color="#FF0000"] {
+  background-color: #FF0000;
+}
+
+.sceditor-color-option[data-color="#800000"] {
+  background-color: #800000;
+}
+
+.sceditor-color-option[data-color="#FFFF00"] {
+  background-color: #FFFF00;
+}
+
+.sceditor-color-option[data-color="#808000"] {
+  background-color: #808000;
+}
+
+.sceditor-color-option[data-color="#00FF00"] {
+  background-color: #00FF00;
+}
+
+.sceditor-color-option[data-color="#008000"] {
+  background-color: #008000;
+}
+
+.sceditor-color-option[data-color="#00FFFF"] {
+  background-color: #00FFFF;
+}
+
+.sceditor-color-option[data-color="#008080"] {
+  background-color: #008080;
+}
+
+.sceditor-color-option[data-color="#0000FF"] {
+  background-color: #0000FF;
+}
+
+.sceditor-color-option[data-color="#000080"] {
+  background-color: #000080;
+}

BIN
public/style/sc/themes/famfamfam.png


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików