Santhosh has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/158369

Change subject: WIP: Format Tool card
......................................................................

WIP: Format Tool card

Don't merge. A quick and minimal functionality is added, just to
find out how it goes

* Remove experimental medium editor

Change-Id: I794d7e6bfcd3792acea6cae6ec00492251018ba7
---
M Resources.php
M modules/editor/ext.cx.editor.js
D modules/editor/medium/medium-editor.css
D modules/editor/medium/medium-editor.js
D modules/editor/medium/theme/agora.css
A modules/tools/ext.cx.tools.formatter.js
A modules/tools/images/bold-b.svg
A modules/tools/images/bullet-list-ltr.svg
A modules/tools/images/bullet-list-rtl.svg
A modules/tools/images/italic-i.svg
A modules/tools/images/number-list-ltr.svg
A modules/tools/images/number-list-rtl.svg
A modules/tools/styles/ext.cx.tools.formatter.less
M specials/SpecialContentTranslation.php
14 files changed, 281 insertions(+), 1,716 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/ContentTranslation 
refs/changes/69/158369/1

diff --git a/Resources.php b/Resources.php
index 9a0ac02..68d0f9f 100644
--- a/Resources.php
+++ b/Resources.php
@@ -122,6 +122,7 @@
        ),
        'dependencies' => array(
                'ext.cx.translation.progress',
+               'ext.cx.editor',
                'jquery.uls.data',
                'mediawiki.Uri',
                'jquery.throttle-debounce',
@@ -164,6 +165,7 @@
                'mediawiki.jqueryMsg',
                'ext.cx.tools.manager',
                'ext.cx.tools.dictionary',
+               'ext.cx.tools.formatter',
                'ext.cx.tools.instructions',
                'ext.cx.tools.link',
                'ext.cx.tools.images',
@@ -217,6 +219,19 @@
                'cx-mt-abuse-warning-text',
                'cx-tools-view-guidelines',
                'cx-tools-view-guidelines-link',
+       ),
+       'dependencies' => array(
+               'ext.cx.tools.manager',
+               'ext.cx.tools.card',
+       ),
+) + $resourcePaths;
+
+$wgResourceModules['ext.cx.tools.formatter'] = array(
+       'scripts' => array(
+               'tools/ext.cx.tools.formatter.js',
+       ),
+       'styles' => array(
+               'tools/styles/ext.cx.tools.formatter.less',
        ),
        'dependencies' => array(
                'ext.cx.tools.manager',
@@ -422,15 +437,3 @@
                'jquery.throttle-debounce',
        ),
 ) + $resourcePaths;
-
-$wgResourceModules['ext.cx.editor.medium'] = array(
-       'scripts' => array(
-               'editor/ext.cx.editor.js',
-               'editor/medium/medium-editor.js',
-       ),
-       'styles' => array(
-               'editor/medium/medium-editor.css',
-               'editor/medium/theme/agora.css',
-       ),
-) + $resourcePaths;
-
diff --git a/modules/editor/ext.cx.editor.js b/modules/editor/ext.cx.editor.js
index 455216a..091f521 100644
--- a/modules/editor/ext.cx.editor.js
+++ b/modules/editor/ext.cx.editor.js
@@ -34,7 +34,6 @@
                }
                // Make the element editable
                this.$editableElement.attr( 'contenteditable', true );
-               this.wysiwygEditor();
        };
 
        /**
@@ -69,38 +68,6 @@
                                return e.which !== 13; // Enter key code
                        } );
                }
-       };
-
-       /**
-        * Enhance the basic content editable with a WYSIWYG editor
-        * MediumEditor is used here. But any such simple editor
-        * can work here.
-        */
-       CXSectionEditor.prototype.wysiwygEditor = function () {
-               var editorOptions;
-
-               if ( !window.MediumEditor ) {
-                       return;
-               }
-               editorOptions = {
-                       cleanPastedHTML: true,
-                       buttons: [ 'bold', 'italic', 'header1', 'header2',
-                               'unorderedlist', 'orderedlist', 'indent', 
'outdent' ],
-                       firstHeader: 'h2',
-                       secondHeader: 'h3',
-                       disableDoubleReturn: true
-               };
-               // Avoid previews on mouse over of links
-               MediumEditor.prototype.editorAnchorObserver = function () {};
-
-               if ( this.$editableElement.get( 0 ).tagName === 'FIGURECAPTION' 
) {
-                       // Prevent pressing return on caption to avoid
-                       // creation of <p> nodes
-                       editorOptions.disableReturn = true;
-               }
-
-               /*jshint -W031 */
-               new MediumEditor( this.$editableElement, editorOptions );
        };
 
        $.fn.cxEditor = function () {
diff --git a/modules/editor/medium/medium-editor.css 
b/modules/editor/medium/medium-editor.css
deleted file mode 100644
index 244f74c..0000000
--- a/modules/editor/medium/medium-editor.css
+++ /dev/null
@@ -1,168 +0,0 @@
-.clearfix:after {
-  display: block;
-  visibility: hidden;
-  clear: both;
-  height: 0;
-  content: " ";
-  font-size: 0; }
-
-@-webkit-keyframes pop-upwards {
-  0% {
-    -webkit-transform: matrix(0.97, 0, 0, 1, 0, 12);
-    transform: matrix(0.97, 0, 0, 1, 0, 12);
-    opacity: 0; }
-
-  20% {
-    -webkit-transform: matrix(0.99, 0, 0, 1, 0, 2);
-    transform: matrix(0.99, 0, 0, 1, 0, 2);
-    opacity: 0.7; }
-
-  40% {
-    -webkit-transform: matrix(1, 0, 0, 1, 0, -1);
-    transform: matrix(1, 0, 0, 1, 0, -1);
-    opacity: 1; }
-
-  70% {
-    -webkit-transform: matrix(1, 0, 0, 1, 0, 0);
-    transform: matrix(1, 0, 0, 1, 0, 0);
-    opacity: 1; }
-
-  100% {
-    -webkit-transform: matrix(1, 0, 0, 1, 0, 0);
-    transform: matrix(1, 0, 0, 1, 0, 0);
-    opacity: 1; } }
-
-@keyframes pop-upwards {
-  0% {
-    -webkit-transform: matrix(0.97, 0, 0, 1, 0, 12);
-    transform: matrix(0.97, 0, 0, 1, 0, 12);
-    opacity: 0; }
-
-  20% {
-    -webkit-transform: matrix(0.99, 0, 0, 1, 0, 2);
-    transform: matrix(0.99, 0, 0, 1, 0, 2);
-    opacity: 0.7; }
-
-  40% {
-    -webkit-transform: matrix(1, 0, 0, 1, 0, -1);
-    transform: matrix(1, 0, 0, 1, 0, -1);
-    opacity: 1; }
-
-  70% {
-    -webkit-transform: matrix(1, 0, 0, 1, 0, 0);
-    transform: matrix(1, 0, 0, 1, 0, 0);
-    opacity: 1; }
-
-  100% {
-    -webkit-transform: matrix(1, 0, 0, 1, 0, 0);
-    transform: matrix(1, 0, 0, 1, 0, 0);
-    opacity: 1; } }
-
-.medium-toolbar-arrow-under:after, .medium-toolbar-arrow-over:before {
-  position: absolute;
-  left: 50%;
-  display: block;
-  margin-left: -8px;
-  width: 0;
-  height: 0;
-  border-style: solid;
-  content: ""; }
-
-.medium-toolbar-arrow-under:after {
-  border-width: 8px 8px 0 8px; }
-
-.medium-toolbar-arrow-over:before {
-  top: -8px;
-  border-width: 0 8px 8px 8px; }
-
-.medium-editor-toolbar, .medium-editor-anchor-preview {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: 2000;
-  visibility: hidden;
-  font-size: 16px;
-  font-family: HelveticaNeue, Helvetica, Arial, sans-serif; }
-  .medium-editor-toolbar ul, .medium-editor-anchor-preview ul {
-    margin: 0;
-    padding: 0; }
-  .medium-editor-toolbar li, .medium-editor-anchor-preview li {
-    float: left;
-    margin: 0;
-    padding: 0;
-    list-style: none; }
-    .medium-editor-toolbar li button, .medium-editor-anchor-preview li button {
-      display: block;
-      margin: 0;
-      padding: 15px;
-      cursor: pointer;
-      font-size: 14px;
-      line-height: 1.33;
-      text-decoration: none;
-      -webkit-box-sizing: border-box;
-      -moz-box-sizing: border-box;
-      box-sizing: border-box; }
-    .medium-editor-toolbar li .medium-editor-action-underline, 
.medium-editor-anchor-preview li .medium-editor-action-underline {
-      text-decoration: underline; }
-    .medium-editor-toolbar li .medium-editor-action-pre, 
.medium-editor-anchor-preview li .medium-editor-action-pre {
-      padding: 15px 0;
-      font-weight: 100;
-      font-size: 12px;
-      font-family: 'Menlo', monospace; }
-
-.medium-editor-anchor-preview i {
-  display: inline-block;
-  margin: 5px 5px 5px 10px;
-  text-decoration: underline;
-  font-style: normal;
-  cursor: pointer; }
-
-.medium-editor-toolbar-active, .medium-editor-anchor-preview-active {
-  visibility: visible;
-  -webkit-animation: pop-upwards 160ms forwards linear;
-  -ms-animation: pop-upwards 160ms forwards linear;
-  animation: pop-upwards 160ms forwards linear;
-  -webkit-transition: top 0.075s ease-out, left 0.075s ease-out;
-  transition: top 0.075s ease-out, left 0.075s ease-out; }
-
-.medium-editor-action-bold {
-  font-weight: bolder; }
-
-.medium-editor-action-italic {
-  font-style: italic; }
-
-.medium-editor-toolbar-form-anchor {
-  display: none; }
-  .medium-editor-toolbar-form-anchor input, .medium-editor-toolbar-form-anchor 
a {
-    font-family: HelveticaNeue, Helvetica, Arial, sans-serif; }
-  .medium-editor-toolbar-form-anchor input {
-    margin: 0;
-    padding: 6px;
-    width: 316px;
-    border: none;
-    font-size: 14px;
-    -webkit-box-sizing: border-box;
-    -moz-box-sizing: border-box;
-    box-sizing: border-box; }
-    .medium-editor-toolbar-form-anchor input:focus {
-      outline: 0;
-      border: none;
-      -webkit-box-shadow: none;
-      box-shadow: none;
-      -webkit-appearance: none;
-      -moz-appearance: none; }
-  .medium-editor-toolbar-form-anchor a {
-    display: inline-block;
-    margin: 0 10px;
-    text-decoration: none;
-    font-weight: bolder;
-    font-size: 24px; }
-
-.medium-editor-placeholder {
-  position: relative; }
-  .medium-editor-placeholder:after {
-    position: absolute;
-    top: 0;
-    left: 0;
-    content: attr(data-placeholder);
-    font-style: italic; }
diff --git a/modules/editor/medium/medium-editor.js 
b/modules/editor/medium/medium-editor.js
deleted file mode 100644
index 8b3caab..0000000
--- a/modules/editor/medium/medium-editor.js
+++ /dev/null
@@ -1,1365 +0,0 @@
-function MediumEditor(elements, options) {
-    'use strict';
-    return this.init(elements, options);
-}
-
-if (typeof module === 'object') {
-    module.exports = MediumEditor;
-}
-
-(function (window, document) {
-    'use strict';
-
-    function extend(b, a) {
-        var prop;
-        if (b === undefined) {
-            return a;
-        }
-        for (prop in a) {
-            if (a.hasOwnProperty(prop) && b.hasOwnProperty(prop) === false) {
-                b[prop] = a[prop];
-            }
-        }
-        return b;
-    }
-
-    // 
http://stackoverflow.com/questions/5605401/insert-link-in-contenteditable-element
-    // by Tim Down
-    function saveSelection() {
-        var i,
-            len,
-            ranges,
-            sel = window.getSelection();
-        if (sel.getRangeAt && sel.rangeCount) {
-            ranges = [];
-            for (i = 0, len = sel.rangeCount; i < len; i += 1) {
-                ranges.push(sel.getRangeAt(i));
-            }
-            return ranges;
-        }
-        return null;
-    }
-
-    function restoreSelection(savedSel) {
-        var i,
-            len,
-            sel = window.getSelection();
-        if (savedSel) {
-            sel.removeAllRanges();
-            for (i = 0, len = savedSel.length; i < len; i += 1) {
-                sel.addRange(savedSel[i]);
-            }
-        }
-    }
-
-    // 
http://stackoverflow.com/questions/1197401/how-can-i-get-the-element-the-caret-is-in-with-javascript-when-using-contentedi
-    // by You
-    function getSelectionStart() {
-        var node = document.getSelection().anchorNode,
-            startNode = (node && node.nodeType === 3 ? node.parentNode : node);
-        return startNode;
-    }
-
-    // http://stackoverflow.com/questions/4176923/html-of-selected-text
-    // by Tim Down
-    function getSelectionHtml() {
-        var i,
-            html = '',
-            sel,
-            len,
-            container;
-        if (window.getSelection !== undefined) {
-            sel = window.getSelection();
-            if (sel.rangeCount) {
-                container = document.createElement('div');
-                for (i = 0, len = sel.rangeCount; i < len; i += 1) {
-                    container.appendChild(sel.getRangeAt(i).cloneContents());
-                }
-                html = container.innerHTML;
-            }
-        } else if (document.selection !== undefined) {
-            if (document.selection.type === 'Text') {
-                html = document.selection.createRange().htmlText;
-            }
-        }
-        return html;
-    }
-
-    // https://github.com/jashkenas/underscore
-    function isElement(obj) {
-        return !!(obj && obj.nodeType === 1);
-    }
-
-    MediumEditor.prototype = {
-        defaults: {
-            allowMultiParagraphSelection: true,
-            anchorInputPlaceholder: 'Paste or type a link',
-            anchorPreviewHideDelay: 500,
-            buttons: ['bold', 'italic', 'underline', 'anchor', 'header1', 
'header2', 'quote'],
-            buttonLabels: false,
-            checkLinkFormat: false,
-            cleanPastedHTML: false,
-            delay: 0,
-            diffLeft: 0,
-            diffTop: -10,
-            disableReturn: false,
-            disableDoubleReturn: false,
-            disableToolbar: false,
-            disableEditing: false,
-            elementsContainer: false,
-            firstHeader: 'h3',
-            forcePlainText: true,
-            placeholder: 'Type your text',
-            secondHeader: 'h4',
-            targetBlank: false,
-            extensions: {},
-            activeButtonClass: 'medium-editor-button-active',
-            firstButtonClass: 'medium-editor-button-first',
-            lastButtonClass: 'medium-editor-button-last'
-        },
-
-        // 
http://stackoverflow.com/questions/17907445/how-to-detect-ie11#comment30165888_17907562
-        // by rg89
-        isIE: ((navigator.appName === 'Microsoft Internet Explorer') || 
((navigator.appName === 'Netscape') && (new 
RegExp('Trident/.*rv:([0-9]{1,}[.0-9]{0,})').exec(navigator.userAgent) !== 
null))),
-
-        init: function (elements, options) {
-            this.setElementSelection(elements);
-            if (this.elements.length === 0) {
-                return;
-            }
-            this.parentElements = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 
'blockquote', 'pre'];
-            this.id = 
document.querySelectorAll('.medium-editor-toolbar').length + 1;
-            this.options = extend(options, this.defaults);
-            return this.setup();
-        },
-
-        setup: function () {
-            this.isActive = true;
-            this.initElements()
-                .bindSelect()
-                .bindPaste()
-                .setPlaceholders()
-                .bindWindowActions();
-        },
-
-        initElements: function () {
-            this.updateElementList();
-            var i,
-                addToolbar = false;
-            for (i = 0; i < this.elements.length; i += 1) {
-                if (!this.options.disableEditing && 
!this.elements[i].getAttribute('data-disable-editing')) {
-                    this.elements[i].setAttribute('contentEditable', true);
-                }
-                if (!this.elements[i].getAttribute('data-placeholder')) {
-                    this.elements[i].setAttribute('data-placeholder', 
this.options.placeholder);
-                }
-                this.elements[i].setAttribute('data-medium-element', true);
-                this.bindParagraphCreation(i).bindReturn(i).bindTab(i);
-                if (!this.options.disableToolbar && 
!this.elements[i].getAttribute('data-disable-toolbar')) {
-                    addToolbar = true;
-                }
-            }
-            // Init toolbar
-            if (addToolbar) {
-                if (!this.options.elementsContainer) {
-                    this.options.elementsContainer = document.body;
-                }
-                this.initToolbar()
-                    .bindButtons()
-                    .bindAnchorForm()
-                    .bindAnchorPreview();
-            }
-            return this;
-        },
-
-        setElementSelection: function (selector) {
-            this.elementSelection = selector;
-            this.updateElementList();
-        },
-
-        updateElementList: function () {
-            this.elements = typeof this.elementSelection === 'string' ? 
document.querySelectorAll(this.elementSelection) : this.elementSelection;
-            if (this.elements.nodeType === 1) {
-                this.elements = [this.elements];
-            }
-        },
-
-        serialize: function () {
-            var i,
-                elementid,
-                content = {};
-            for (i = 0; i < this.elements.length; i += 1) {
-                elementid = (this.elements[i].id !== '') ? this.elements[i].id 
: 'element-' + i;
-                content[elementid] = {
-                    value: this.elements[i].innerHTML.trim()
-                };
-            }
-            return content;
-        },
-
-        /**
-         * Helper function to call a method with a number of parameters on all 
registered extensions.
-         * The function assures that the function exists before calling.
-         *
-         * @param {string} funcName name of the function to call
-         * @param [args] arguments passed into funcName
-         */
-        callExtensions: function (funcName) {
-            if (arguments.length < 1) {
-                return;
-            }
-
-            var args = Array.prototype.slice.call(arguments, 1),
-                ext,
-                name;
-
-            for (name in this.options.extensions) {
-                if (this.options.extensions.hasOwnProperty(name)) {
-                    ext = this.options.extensions[name];
-                    if (ext[funcName] !== undefined) {
-                        ext[funcName].apply(ext, args);
-                    }
-                }
-            }
-        },
-
-        bindParagraphCreation: function (index) {
-            var self = this;
-            this.elements[index].addEventListener('keypress', function (e) {
-                var node = getSelectionStart(),
-                    tagName;
-                if (e.which === 32) {
-                    tagName = node.tagName.toLowerCase();
-                    if (tagName === 'a') {
-                        document.execCommand('unlink', false, null);
-                    }
-                }
-            });
-
-            this.elements[index].addEventListener('keyup', function (e) {
-                var node = getSelectionStart(),
-                    tagName;
-                if (node && node.getAttribute('data-medium-element') && 
node.children.length === 0 && !(self.options.disableReturn || 
node.getAttribute('data-disable-return'))) {
-                    document.execCommand('formatBlock', false, 'p');
-                }
-                if (e.which === 13) {
-                    node = getSelectionStart();
-                    tagName = node.tagName.toLowerCase();
-                    if (!(self.options.disableReturn || 
this.getAttribute('data-disable-return')) &&
-                        tagName !== 'li' && !self.isListItemChild(node)) {
-                        if (!e.shiftKey) {
-                            document.execCommand('formatBlock', false, 'p');
-                        }
-                        if (tagName === 'a') {
-                            document.execCommand('unlink', false, null);
-                        }
-                    }
-                }
-            });
-            return this;
-        },
-
-        isListItemChild: function (node) {
-            var parentNode = node.parentNode,
-                tagName = parentNode.tagName.toLowerCase();
-            while (this.parentElements.indexOf(tagName) === -1 && tagName !== 
'div') {
-                if (tagName === 'li') {
-                    return true;
-                }
-                parentNode = parentNode.parentNode;
-                if (parentNode && parentNode.tagName) {
-                    tagName = parentNode.tagName.toLowerCase();
-                } else {
-                    return false;
-                }
-            }
-            return false;
-        },
-
-        bindReturn: function (index) {
-            var self = this;
-            this.elements[index].addEventListener('keypress', function (e) {
-                if (e.which === 13) {
-                    if (self.options.disableReturn || 
this.getAttribute('data-disable-return')) {
-                        e.preventDefault();
-                    } else if (self.options.disableDoubleReturn || 
this.getAttribute('data-disable-double-return')) {
-                        var node = getSelectionStart();
-                        if (node && node.innerText === '\n') {
-                            e.preventDefault();
-                        }
-                    }
-                }
-            });
-            return this;
-        },
-
-        bindTab: function (index) {
-            this.elements[index].addEventListener('keydown', function (e) {
-                if (e.which === 9) {
-                    // Override tab only for pre nodes
-                    var tag = getSelectionStart().tagName.toLowerCase();
-                    if (tag === 'pre') {
-                        e.preventDefault();
-                        document.execCommand('insertHtml', null, '    ');
-                    }
-                }
-            });
-            return this;
-        },
-
-        buttonTemplate: function (btnType) {
-            var buttonLabels = this.getButtonLabels(this.options.buttonLabels),
-                buttonTemplates = {
-                    'bold': '<button class="medium-editor-action 
medium-editor-action-bold" data-action="bold" data-element="b">' + 
buttonLabels.bold + '</button>',
-                    'italic': '<button class="medium-editor-action 
medium-editor-action-italic" data-action="italic" data-element="i">' + 
buttonLabels.italic + '</button>',
-                    'underline': '<button class="medium-editor-action 
medium-editor-action-underline" data-action="underline" data-element="u">' + 
buttonLabels.underline + '</button>',
-                    'strikethrough': '<button class="medium-editor-action 
medium-editor-action-strikethrough" data-action="strikethrough" 
data-element="strike"><strike>A</strike></button>',
-                    'superscript': '<button class="medium-editor-action 
medium-editor-action-superscript" data-action="superscript" 
data-element="sup">' + buttonLabels.superscript + '</button>',
-                    'subscript': '<button class="medium-editor-action 
medium-editor-action-subscript" data-action="subscript" data-element="sub">' + 
buttonLabels.subscript + '</button>',
-                    'anchor': '<button class="medium-editor-action 
medium-editor-action-anchor" data-action="anchor" data-element="a">' + 
buttonLabels.anchor + '</button>',
-                    'image': '<button class="medium-editor-action 
medium-editor-action-image" data-action="image" data-element="img">' + 
buttonLabels.image + '</button>',
-                    'header1': '<button class="medium-editor-action 
medium-editor-action-header1" data-action="append-' + this.options.firstHeader 
+ '" data-element="' + this.options.firstHeader + '">' + buttonLabels.header1 + 
'</button>',
-                    'header2': '<button class="medium-editor-action 
medium-editor-action-header2" data-action="append-' + this.options.secondHeader 
+ '" data-element="' + this.options.secondHeader + '">' + buttonLabels.header2 
+ '</button>',
-                    'quote': '<button class="medium-editor-action 
medium-editor-action-quote" data-action="append-blockquote" 
data-element="blockquote">' + buttonLabels.quote + '</button>',
-                    'orderedlist': '<button class="medium-editor-action 
medium-editor-action-orderedlist" data-action="insertorderedlist" 
data-element="ol">' + buttonLabels.orderedlist + '</button>',
-                    'unorderedlist': '<button class="medium-editor-action 
medium-editor-action-unorderedlist" data-action="insertunorderedlist" 
data-element="ul">' + buttonLabels.unorderedlist + '</button>',
-                    'pre': '<button class="medium-editor-action 
medium-editor-action-pre" data-action="append-pre" data-element="pre">' + 
buttonLabels.pre + '</button>',
-                    'indent': '<button class="medium-editor-action 
medium-editor-action-indent" data-action="indent" data-element="ul">' + 
buttonLabels.indent + '</button>',
-                    'outdent': '<button class="medium-editor-action 
medium-editor-action-outdent" data-action="outdent" data-element="ul">' + 
buttonLabels.outdent + '</button>'
-                };
-            return buttonTemplates[btnType] || false;
-        },
-
-        // TODO: break method
-        getButtonLabels: function (buttonLabelType) {
-            var customButtonLabels,
-                attrname,
-                buttonLabels = {
-                    'bold': '<b>B</b>',
-                    'italic': '<b><i>I</i></b>',
-                    'underline': '<b><u>U</u></b>',
-                    'superscript': '<b>x<sup>1</sup></b>',
-                    'subscript': '<b>x<sub>1</sub></b>',
-                    'anchor': '<b>#</b>',
-                    'image': '<b>image</b>',
-                    'header1': '<b>H1</b>',
-                    'header2': '<b>H2</b>',
-                    'quote': '<b>&ldquo;</b>',
-                    'orderedlist': '<b>1.</b>',
-                    'unorderedlist': '<b>&bull;</b>',
-                    'pre': '<b>0101</b>',
-                    'indent': '<b>&rarr;</b>',
-                    'outdent': '<b>&larr;</b>'
-                };
-            if (buttonLabelType === 'fontawesome') {
-                customButtonLabels = {
-                    'bold': '<i class="fa fa-bold"></i>',
-                    'italic': '<i class="fa fa-italic"></i>',
-                    'underline': '<i class="fa fa-underline"></i>',
-                    'superscript': '<i class="fa fa-superscript"></i>',
-                    'subscript': '<i class="fa fa-subscript"></i>',
-                    'anchor': '<i class="fa fa-link"></i>',
-                    'image': '<i class="fa fa-picture-o"></i>',
-                    'quote': '<i class="fa fa-quote-right"></i>',
-                    'orderedlist': '<i class="fa fa-list-ol"></i>',
-                    'unorderedlist': '<i class="fa fa-list-ul"></i>',
-                    'pre': '<i class="fa fa-code fa-lg"></i>',
-                    'indent': '<i class="fa fa-indent"></i>',
-                    'outdent': '<i class="fa fa-outdent"></i>'
-                };
-            } else if (typeof buttonLabelType === 'object') {
-                customButtonLabels = buttonLabelType;
-            }
-            if (typeof customButtonLabels === 'object') {
-                for (attrname in customButtonLabels) {
-                    if (customButtonLabels.hasOwnProperty(attrname)) {
-                        buttonLabels[attrname] = customButtonLabels[attrname];
-                    }
-                }
-            }
-            return buttonLabels;
-        },
-
-        initToolbar: function () {
-            if (this.toolbar) {
-                return this;
-            }
-            this.toolbar = this.createToolbar();
-            this.keepToolbarAlive = false;
-            this.anchorForm = 
this.toolbar.querySelector('.medium-editor-toolbar-form-anchor');
-            this.anchorInput = this.anchorForm.querySelector('input');
-            this.toolbarActions = 
this.toolbar.querySelector('.medium-editor-toolbar-actions');
-            this.anchorPreview = this.createAnchorPreview();
-
-            return this;
-        },
-
-        createToolbar: function () {
-            var toolbar = document.createElement('div');
-            toolbar.id = 'medium-editor-toolbar-' + this.id;
-            toolbar.className = 'medium-editor-toolbar';
-            toolbar.appendChild(this.toolbarButtons());
-            toolbar.appendChild(this.toolbarFormAnchor());
-            this.options.elementsContainer.appendChild(toolbar);
-            return toolbar;
-        },
-
-        //TODO: actionTemplate
-        toolbarButtons: function () {
-            var btns = this.options.buttons,
-                ul = document.createElement('ul'),
-                li,
-                i,
-                btn,
-                ext;
-
-            ul.id = 'medium-editor-toolbar-actions';
-            ul.className = 'medium-editor-toolbar-actions clearfix';
-
-            for (i = 0; i < btns.length; i += 1) {
-                if (this.options.extensions.hasOwnProperty(btns[i])) {
-                    ext = this.options.extensions[btns[i]];
-                    btn = ext.getButton !== undefined ? ext.getButton() : null;
-                } else {
-                    btn = this.buttonTemplate(btns[i]);
-                }
-
-                if (btn) {
-                    li = document.createElement('li');
-                    if (isElement(btn)) {
-                        li.appendChild(btn);
-                    } else {
-                        li.innerHTML = btn;
-                    }
-                    ul.appendChild(li);
-                }
-            }
-
-            return ul;
-        },
-
-        toolbarFormAnchor: function () {
-            var anchor = document.createElement('div'),
-                input = document.createElement('input'),
-                a = document.createElement('a');
-
-            a.setAttribute('href', '#');
-            a.innerHTML = '&times;';
-
-            input.setAttribute('type', 'text');
-            input.setAttribute('placeholder', 
this.options.anchorInputPlaceholder);
-
-            anchor.className = 'medium-editor-toolbar-form-anchor';
-            anchor.id = 'medium-editor-toolbar-form-anchor';
-            anchor.appendChild(input);
-            anchor.appendChild(a);
-
-            return anchor;
-        },
-
-        bindSelect: function () {
-            var self = this,
-                timer = '',
-                i;
-
-            this.checkSelectionWrapper = function (e) {
-
-                // Do not close the toolbar when bluring the editable area and 
clicking into the anchor form
-                if (e && self.clickingIntoArchorForm(e)) {
-                    return false;
-                }
-
-                clearTimeout(timer);
-                timer = setTimeout(function () {
-                    self.checkSelection();
-                }, self.options.delay);
-            };
-
-            document.documentElement.addEventListener('mouseup', 
this.checkSelectionWrapper);
-
-            for (i = 0; i < this.elements.length; i += 1) {
-                this.elements[i].addEventListener('keyup', 
this.checkSelectionWrapper);
-                this.elements[i].addEventListener('blur', 
this.checkSelectionWrapper);
-            }
-            return this;
-        },
-
-        checkSelection: function () {
-            var newSelection,
-                selectionElement;
-
-            if (this.keepToolbarAlive !== true && 
!this.options.disableToolbar) {
-                newSelection = window.getSelection();
-                if (newSelection.toString().trim() === '' ||
-                    (this.options.allowMultiParagraphSelection === false && 
this.hasMultiParagraphs())) {
-                    this.hideToolbarActions();
-                } else {
-                    selectionElement = this.getSelectionElement();
-                    if (!selectionElement || 
selectionElement.getAttribute('data-disable-toolbar')) {
-                        this.hideToolbarActions();
-                    } else {
-                        this.checkSelectionElement(newSelection, 
selectionElement);
-                    }
-                }
-            }
-            return this;
-        },
-
-        clickingIntoArchorForm: function (e) {
-            var self = this;
-            if (e.type && e.type.toLowerCase() === 'blur' && e.relatedTarget 
&& e.relatedTarget === self.anchorInput) {
-                return true;
-            }
-            return false;
-        },
-
-        hasMultiParagraphs: function () {
-            var selectionHtml = 
getSelectionHtml().replace(/<[\S]+><\/[\S]+>/gim, ''),
-                hasMultiParagraphs = 
selectionHtml.match(/<(p|h[0-6]|blockquote)>([\s\S]*?)<\/(p|h[0-6]|blockquote)>/g);
-
-            return (hasMultiParagraphs ? hasMultiParagraphs.length : 0);
-        },
-
-        checkSelectionElement: function (newSelection, selectionElement) {
-            var i;
-            this.selection = newSelection;
-            this.selectionRange = this.selection.getRangeAt(0);
-            for (i = 0; i < this.elements.length; i += 1) {
-                if (this.elements[i] === selectionElement) {
-                    this.setToolbarButtonStates()
-                        .setToolbarPosition()
-                        .showToolbarActions();
-                    return;
-                }
-            }
-            this.hideToolbarActions();
-        },
-
-        getSelectionElement: function () {
-            var selection = window.getSelection(),
-                range, current, parent,
-                result,
-                getMediumElement = function (e) {
-                    var localParent = e;
-                    try {
-                        while 
(!localParent.getAttribute('data-medium-element')) {
-                            localParent = localParent.parentNode;
-                        }
-                    } catch (errb) {
-                        return false;
-                    }
-                    return localParent;
-                };
-            // First try on current node
-            try {
-                range = selection.getRangeAt(0);
-                current = range.commonAncestorContainer;
-                parent = current.parentNode;
-
-                if (current.getAttribute('data-medium-element')) {
-                    result = current;
-                } else {
-                    result = getMediumElement(parent);
-                }
-                // If not search in the parent nodes.
-            } catch (err) {
-                result = getMediumElement(parent);
-            }
-            return result;
-        },
-
-        setToolbarPosition: function () {
-            var buttonHeight = 50,
-                selection = window.getSelection(),
-                range = selection.getRangeAt(0),
-                boundary = range.getBoundingClientRect(),
-                defaultLeft = (this.options.diffLeft) - 
(this.toolbar.offsetWidth / 2),
-                middleBoundary = (boundary.left + boundary.right) / 2,
-                halfOffsetWidth = this.toolbar.offsetWidth / 2;
-            if (boundary.top < buttonHeight) {
-                this.toolbar.classList.add('medium-toolbar-arrow-over');
-                this.toolbar.classList.remove('medium-toolbar-arrow-under');
-                this.toolbar.style.top = buttonHeight + boundary.bottom - 
this.options.diffTop + window.pageYOffset - this.toolbar.offsetHeight + 'px';
-            } else {
-                this.toolbar.classList.add('medium-toolbar-arrow-under');
-                this.toolbar.classList.remove('medium-toolbar-arrow-over');
-                this.toolbar.style.top = boundary.top + this.options.diffTop + 
window.pageYOffset - this.toolbar.offsetHeight + 'px';
-            }
-            if (middleBoundary < halfOffsetWidth) {
-                this.toolbar.style.left = defaultLeft + halfOffsetWidth + 'px';
-            } else if ((window.innerWidth - middleBoundary) < halfOffsetWidth) 
{
-                this.toolbar.style.left = window.innerWidth + defaultLeft - 
halfOffsetWidth + 'px';
-            } else {
-                this.toolbar.style.left = defaultLeft + middleBoundary + 'px';
-            }
-
-            this.hideAnchorPreview();
-
-            return this;
-        },
-
-        setToolbarButtonStates: function () {
-            var buttons = this.toolbarActions.querySelectorAll('button'),
-                i;
-            for (i = 0; i < buttons.length; i += 1) {
-                buttons[i].classList.remove(this.options.activeButtonClass);
-            }
-            this.checkActiveButtons();
-            return this;
-        },
-
-        checkActiveButtons: function () {
-            var elements = Array.prototype.slice.call(this.elements),
-                parentNode = this.getSelectedParentElement();
-            while (parentNode.tagName !== undefined && 
this.parentElements.indexOf(parentNode.tagName.toLowerCase) === -1) {
-                this.activateButton(parentNode.tagName.toLowerCase());
-                this.callExtensions('checkState', parentNode);
-
-                // we can abort the search upwards if we leave the 
contentEditable element
-                if (elements.indexOf(parentNode) !== -1) {
-                    break;
-                }
-                parentNode = parentNode.parentNode;
-            }
-        },
-
-        activateButton: function (tag) {
-            var el = this.toolbar.querySelector('[data-element="' + tag + 
'"]');
-            if (el !== null && 
el.className.indexOf(this.options.activeButtonClass) === -1) {
-                el.className += ' ' + this.options.activeButtonClass;
-            }
-        },
-
-        bindButtons: function () {
-            var buttons = this.toolbar.querySelectorAll('button'),
-                i,
-                self = this,
-                triggerAction = function (e) {
-                    e.preventDefault();
-                    e.stopPropagation();
-                    if (self.selection === undefined) {
-                        self.checkSelection();
-                    }
-                    if (this.className.indexOf(self.options.activeButtonClass) 
> -1) {
-                        this.classList.remove(self.options.activeButtonClass);
-                    } else {
-                        this.className += ' ' + self.options.activeButtonClass;
-                    }
-                    if (this.hasAttribute('data-action')) {
-                        self.execAction(this.getAttribute('data-action'), e);
-                    }
-                };
-            for (i = 0; i < buttons.length; i += 1) {
-                buttons[i].addEventListener('click', triggerAction);
-            }
-            this.setFirstAndLastItems(buttons);
-            return this;
-        },
-
-        setFirstAndLastItems: function (buttons) {
-            if (buttons.length > 0) {
-                buttons[0].className += ' ' + this.options.firstButtonClass;
-                buttons[buttons.length - 1].className += ' ' + 
this.options.lastButtonClass;
-            }
-            return this;
-        },
-
-        execAction: function (action, e) {
-            if (action.indexOf('append-') > -1) {
-                this.execFormatBlock(action.replace('append-', ''));
-                this.setToolbarPosition();
-                this.setToolbarButtonStates();
-            } else if (action === 'anchor') {
-                this.triggerAnchorAction(e);
-            } else if (action === 'image') {
-                document.execCommand('insertImage', false, 
window.getSelection());
-            } else {
-                document.execCommand(action, false, null);
-                this.setToolbarPosition();
-            }
-        },
-
-        // 
http://stackoverflow.com/questions/15867542/range-object-get-selection-parent-node-chrome-vs-firefox
-        rangeSelectsSingleNode: function (range) {
-            var startNode = range.startContainer;
-            return startNode === range.endContainer &&
-                startNode.hasChildNodes() &&
-                range.endOffset === range.startOffset + 1;
-        },
-
-        getSelectedParentElement: function () {
-            var selectedParentElement = null,
-                range = this.selectionRange;
-            if (this.rangeSelectsSingleNode(range)) {
-                selectedParentElement = 
range.startContainer.childNodes[range.startOffset];
-            } else if (range.startContainer.nodeType === 3) {
-                selectedParentElement = range.startContainer.parentNode;
-            } else {
-                selectedParentElement = range.startContainer;
-            }
-            return selectedParentElement;
-        },
-
-        triggerAnchorAction: function () {
-            var selectedParentElement = this.getSelectedParentElement();
-            if (selectedParentElement.tagName &&
-                    selectedParentElement.tagName.toLowerCase() === 'a') {
-                document.execCommand('unlink', false, null);
-            } else {
-                if (this.anchorForm.style.display === 'block') {
-                    this.showToolbarActions();
-                } else {
-                    this.showAnchorForm();
-                }
-            }
-            return this;
-        },
-
-        execFormatBlock: function (el) {
-            var selectionData = 
this.getSelectionData(this.selection.anchorNode);
-            // FF handles blockquote differently on formatBlock
-            // allowing nesting, we need to use outdent
-            // 
https://developer.mozilla.org/en-US/docs/Rich-Text_Editing_in_Mozilla
-            if (el === 'blockquote' && selectionData.el &&
-                selectionData.el.parentNode.tagName.toLowerCase() === 
'blockquote') {
-                return document.execCommand('outdent', false, null);
-            }
-            if (selectionData.tagName === el) {
-                el = 'p';
-            }
-            // When IE we need to add <> to heading elements and
-            //  blockquote needs to be called as indent
-            // 
http://stackoverflow.com/questions/10741831/execcommand-formatblock-headings-in-ie
-            // 
http://stackoverflow.com/questions/1816223/rich-text-editor-with-blockquote-function/1821777#1821777
-            if (this.isIE) {
-                if (el === 'blockquote') {
-                    return document.execCommand('indent', false, el);
-                }
-                el = '<' + el + '>';
-            }
-            return document.execCommand('formatBlock', false, el);
-        },
-
-        getSelectionData: function (el) {
-            var tagName;
-
-            if (el && el.tagName) {
-                tagName = el.tagName.toLowerCase();
-            }
-
-            while (el && this.parentElements.indexOf(tagName) === -1) {
-                el = el.parentNode;
-                if (el && el.tagName) {
-                    tagName = el.tagName.toLowerCase();
-                }
-            }
-
-            return {
-                el: el,
-                tagName: tagName
-            };
-        },
-
-        getFirstChild: function (el) {
-            var firstChild = el.firstChild;
-            while (firstChild !== null && firstChild.nodeType !== 1) {
-                firstChild = firstChild.nextSibling;
-            }
-            return firstChild;
-        },
-
-        hideToolbarActions: function () {
-            this.keepToolbarAlive = false;
-            if (this.toolbar !== undefined) {
-                this.toolbar.classList.remove('medium-editor-toolbar-active');
-            }
-        },
-
-        showToolbarActions: function () {
-            var self = this,
-                timer;
-            this.anchorForm.style.display = 'none';
-            this.toolbarActions.style.display = 'block';
-            this.keepToolbarAlive = false;
-            clearTimeout(timer);
-            timer = setTimeout(function () {
-                if (self.toolbar && 
!self.toolbar.classList.contains('medium-editor-toolbar-active')) {
-                    self.toolbar.classList.add('medium-editor-toolbar-active');
-                }
-            }, 100);
-        },
-
-        saveSelection: function() {
-            this.savedSelection = saveSelection();
-        },
-
-        restoreSelection: function() {
-            restoreSelection(this.savedSelection);
-        },
-
-        showAnchorForm: function (link_value) {
-            this.toolbarActions.style.display = 'none';
-            this.saveSelection();
-            this.anchorForm.style.display = 'block';
-            this.keepToolbarAlive = true;
-            this.anchorInput.focus();
-            this.anchorInput.value = link_value || '';
-        },
-
-        bindAnchorForm: function () {
-            var linkCancel = this.anchorForm.querySelector('a'),
-                self = this;
-            this.anchorForm.addEventListener('click', function (e) {
-                e.stopPropagation();
-            });
-            this.anchorInput.addEventListener('keyup', function (e) {
-                if (e.keyCode === 13) {
-                    e.preventDefault();
-                    self.createLink(this);
-                }
-            });
-            this.anchorInput.addEventListener('click', function (e) {
-                // make sure not to hide form when cliking into the input
-                e.stopPropagation();
-                self.keepToolbarAlive = true;
-            });
-            this.anchorInput.addEventListener('blur', function () {
-                self.keepToolbarAlive = false;
-                self.checkSelection();
-            });
-            linkCancel.addEventListener('click', function (e) {
-                e.preventDefault();
-                self.showToolbarActions();
-                restoreSelection(self.savedSelection);
-            });
-            return this;
-        },
-
-
-        hideAnchorPreview: function () {
-            
this.anchorPreview.classList.remove('medium-editor-anchor-preview-active');
-        },
-
-        // TODO: break method
-        showAnchorPreview: function (anchorEl) {
-            if 
(this.anchorPreview.classList.contains('medium-editor-anchor-preview-active')) {
-                return true;
-            }
-
-            var self = this,
-                buttonHeight = 40,
-                boundary = anchorEl.getBoundingClientRect(),
-                middleBoundary = (boundary.left + boundary.right) / 2,
-                halfOffsetWidth,
-                defaultLeft,
-                timer;
-
-            self.anchorPreview.querySelector('i').textContent = anchorEl.href;
-            halfOffsetWidth = self.anchorPreview.offsetWidth / 2;
-            defaultLeft = self.options.diffLeft - halfOffsetWidth;
-
-            clearTimeout(timer);
-            timer = setTimeout(function () {
-                if (self.anchorPreview && 
!self.anchorPreview.classList.contains('medium-editor-anchor-preview-active')) {
-                    
self.anchorPreview.classList.add('medium-editor-anchor-preview-active');
-                }
-            }, 100);
-
-            self.observeAnchorPreview(anchorEl);
-
-            self.anchorPreview.classList.add('medium-toolbar-arrow-over');
-            self.anchorPreview.classList.remove('medium-toolbar-arrow-under');
-            self.anchorPreview.style.top = Math.round(buttonHeight + 
boundary.bottom - self.options.diffTop + window.pageYOffset - 
self.anchorPreview.offsetHeight) + 'px';
-            if (middleBoundary < halfOffsetWidth) {
-                self.anchorPreview.style.left = defaultLeft + halfOffsetWidth 
+ 'px';
-            } else if ((window.innerWidth - middleBoundary) < halfOffsetWidth) 
{
-                self.anchorPreview.style.left = window.innerWidth + 
defaultLeft - halfOffsetWidth + 'px';
-            } else {
-                self.anchorPreview.style.left = defaultLeft + middleBoundary + 
'px';
-            }
-
-            return this;
-        },
-
-        // TODO: break method
-        observeAnchorPreview: function (anchorEl) {
-            var self = this,
-                lastOver = (new Date()).getTime(),
-                over = true,
-                stamp = function () {
-                    lastOver = (new Date()).getTime();
-                    over = true;
-                },
-                unstamp = function (e) {
-                    if (!e.relatedTarget || 
!/anchor-preview/.test(e.relatedTarget.className)) {
-                        over = false;
-                    }
-                },
-                interval_timer = setInterval(function () {
-                    if (over) {
-                        return true;
-                    }
-                    var durr = (new Date()).getTime() - lastOver;
-                    if (durr > self.options.anchorPreviewHideDelay) {
-                        // hide the preview 1/2 second after mouse leaves the 
link
-                        self.hideAnchorPreview();
-
-                        // cleanup
-                        clearInterval(interval_timer);
-                        self.anchorPreview.removeEventListener('mouseover', 
stamp);
-                        self.anchorPreview.removeEventListener('mouseout', 
unstamp);
-                        anchorEl.removeEventListener('mouseover', stamp);
-                        anchorEl.removeEventListener('mouseout', unstamp);
-
-                    }
-                }, 200);
-
-            self.anchorPreview.addEventListener('mouseover', stamp);
-            self.anchorPreview.addEventListener('mouseout', unstamp);
-            anchorEl.addEventListener('mouseover', stamp);
-            anchorEl.addEventListener('mouseout', unstamp);
-        },
-
-        createAnchorPreview: function () {
-            var self = this,
-                anchorPreview = document.createElement('div');
-
-            anchorPreview.id = 'medium-editor-anchor-preview-' + this.id;
-            anchorPreview.className = 'medium-editor-anchor-preview';
-            anchorPreview.innerHTML = this.anchorPreviewTemplate();
-            this.options.elementsContainer.appendChild(anchorPreview);
-
-            anchorPreview.addEventListener('click', function () {
-                self.anchorPreviewClickHandler();
-            });
-
-            return anchorPreview;
-        },
-
-        anchorPreviewTemplate: function () {
-            return '<div class="medium-editor-toolbar-anchor-preview" 
id="medium-editor-toolbar-anchor-preview">' +
-                '    <i 
class="medium-editor-toolbar-anchor-preview-inner"></i>' +
-                '</div>';
-        },
-
-        anchorPreviewClickHandler: function (e) {
-            if (this.activeAnchor) {
-
-                var self = this,
-                    range = document.createRange(),
-                    sel = window.getSelection();
-
-                range.selectNodeContents(self.activeAnchor);
-                sel.removeAllRanges();
-                sel.addRange(range);
-                setTimeout(function () {
-                    if (self.activeAnchor) {
-                        self.showAnchorForm(self.activeAnchor.href);
-                    }
-                    self.keepToolbarAlive = false;
-                }, 100 + self.options.delay);
-
-            }
-
-            this.hideAnchorPreview();
-        },
-
-        editorAnchorObserver: function (e) {
-            var self = this,
-                overAnchor = true,
-                leaveAnchor = function () {
-                    // mark the anchor as no longer hovered, and stop listening
-                    overAnchor = false;
-                    self.activeAnchor.removeEventListener('mouseout', 
leaveAnchor);
-                };
-
-            if (e.target && e.target.tagName.toLowerCase() === 'a') {
-
-                // Detect empty href attributes
-                // The browser will make href="" or href="#top"
-                // into absolute urls when accessed as e.targed.href, so check 
the html
-                if (!/href=["']\S+["']/.test(e.target.outerHTML) || 
/href=["']#\S+["']/.test(e.target.outerHTML)) {
-                    return true;
-                }
-
-                // only show when hovering on anchors
-                if 
(this.toolbar.classList.contains('medium-editor-toolbar-active')) {
-                    // only show when toolbar is not present
-                    return true;
-                }
-                this.activeAnchor = e.target;
-                this.activeAnchor.addEventListener('mouseout', leaveAnchor);
-                // show the anchor preview according to the configured delay
-                // if the mouse has not left the anchor tag in that time
-                setTimeout(function () {
-                    if (overAnchor) {
-                        self.showAnchorPreview(e.target);
-                    }
-                }, self.options.delay);
-
-
-            }
-        },
-
-        bindAnchorPreview: function (index) {
-            var i, self = this;
-            this.editorAnchorObserverWrapper = function (e) {
-                self.editorAnchorObserver(e);
-            };
-            for (i = 0; i < this.elements.length; i += 1) {
-                this.elements[i].addEventListener('mouseover', 
this.editorAnchorObserverWrapper);
-            }
-            return this;
-        },
-
-        checkLinkFormat: function (value) {
-            var re = /^https?:\/\//;
-            if (value.match(re)) {
-                return value;
-            }
-            return "http://"; + value;
-        },
-
-        setTargetBlank: function () {
-            var el = getSelectionStart(),
-                i;
-            if (el.tagName.toLowerCase() === 'a') {
-                el.target = '_blank';
-            } else {
-                el = el.getElementsByTagName('a');
-                for (i = 0; i < el.length; i += 1) {
-                    el[i].target = '_blank';
-                }
-            }
-        },
-
-        createLink: function (input) {
-            if (input.value.trim().length === 0) {
-                this.hideToolbarActions();
-                return;
-            }
-            restoreSelection(this.savedSelection);
-            if (this.options.checkLinkFormat) {
-                input.value = this.checkLinkFormat(input.value);
-            }
-            document.execCommand('createLink', false, input.value);
-            if (this.options.targetBlank) {
-                this.setTargetBlank();
-            }
-            this.checkSelection();
-            this.showToolbarActions();
-            input.value = '';
-        },
-
-        bindWindowActions: function () {
-            var timerResize,
-                self = this;
-            this.windowResizeHandler = function () {
-                clearTimeout(timerResize);
-                timerResize = setTimeout(function () {
-                    if (self.toolbar && 
self.toolbar.classList.contains('medium-editor-toolbar-active')) {
-                        self.setToolbarPosition();
-                    }
-                }, 100);
-            };
-            window.addEventListener('resize', this.windowResizeHandler);
-            return this;
-        },
-
-        activate: function () {
-            if (this.isActive) {
-                return;
-            }
-
-            this.setup();
-        },
-
-        // TODO: break method
-        deactivate: function () {
-            var i;
-            if (!this.isActive) {
-                return;
-            }
-            this.isActive = false;
-
-            if (this.toolbar !== undefined) {
-                this.options.elementsContainer.removeChild(this.anchorPreview);
-                this.options.elementsContainer.removeChild(this.toolbar);
-                delete this.toolbar;
-                delete this.anchorPreview;
-            }
-
-            document.documentElement.removeEventListener('mouseup', 
this.checkSelectionWrapper);
-            window.removeEventListener('resize', this.windowResizeHandler);
-
-            for (i = 0; i < this.elements.length; i += 1) {
-                this.elements[i].removeEventListener('mouseover', 
this.editorAnchorObserverWrapper);
-                this.elements[i].removeEventListener('keyup', 
this.checkSelectionWrapper);
-                this.elements[i].removeEventListener('blur', 
this.checkSelectionWrapper);
-                this.elements[i].removeEventListener('paste', 
this.pasteWrapper);
-                this.elements[i].removeAttribute('contentEditable');
-                this.elements[i].removeAttribute('data-medium-element');
-            }
-
-        },
-
-        htmlEntities: function (str) {
-            // converts special characters (like <) into their escaped/encoded 
values (like &lt;).
-            // This allows you to show to display the string without the 
browser reading it as HTML.
-            return String(str).replace(/&/g, '&amp;').replace(/</g, 
'&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
-        },
-
-        bindPaste: function () {
-            var i, self = this;
-            this.pasteWrapper = function (e) {
-                var paragraphs,
-                    html = '',
-                    p;
-
-                this.classList.remove('medium-editor-placeholder');
-                if (!self.options.forcePlainText && 
!self.options.cleanPastedHTML) {
-                    return this;
-                }
-
-                if (e.clipboardData && e.clipboardData.getData && 
!e.defaultPrevented) {
-                    e.preventDefault();
-
-                    if (self.options.cleanPastedHTML && 
e.clipboardData.getData('text/html')) {
-                        return 
self.cleanPaste(e.clipboardData.getData('text/html'));
-                    }
-                    if (!(self.options.disableReturn || 
this.getAttribute('data-disable-return'))) {
-                        paragraphs = 
e.clipboardData.getData('text/plain').split(/[\r\n]/g);
-                        for (p = 0; p < paragraphs.length; p += 1) {
-                            if (paragraphs[p] !== '') {
-                                if (navigator.userAgent.match(/firefox/i) && p 
=== 0) {
-                                    html += self.htmlEntities(paragraphs[p]);
-                                } else {
-                                    html += '<p>' + 
self.htmlEntities(paragraphs[p]) + '</p>';
-                                }
-                            }
-                        }
-                        document.execCommand('insertHTML', false, html);
-                    } else {
-                        document.execCommand('insertHTML', false, 
e.clipboardData.getData('text/plain'));
-                    }
-                }
-            };
-            for (i = 0; i < this.elements.length; i += 1) {
-                this.elements[i].addEventListener('paste', this.pasteWrapper);
-            }
-            return this;
-        },
-
-        setPlaceholders: function () {
-            var i,
-                activatePlaceholder = function (el) {
-                    if (!(el.querySelector('img')) &&
-                            !(el.querySelector('blockquote')) &&
-                            el.textContent.replace(/^\s+|\s+$/g, '') === '') {
-                        el.classList.add('medium-editor-placeholder');
-                    }
-                },
-                placeholderWrapper = function (e) {
-                    this.classList.remove('medium-editor-placeholder');
-                    if (e.type !== 'keypress') {
-                        activatePlaceholder(this);
-                    }
-                };
-            for (i = 0; i < this.elements.length; i += 1) {
-                activatePlaceholder(this.elements[i]);
-                this.elements[i].addEventListener('blur', placeholderWrapper);
-                this.elements[i].addEventListener('keypress', 
placeholderWrapper);
-            }
-            return this;
-        },
-
-        cleanPaste: function (text) {
-
-            /*jslint regexp: true*/
-            /*
-                jslint does not allow character negation, because the negation
-                will not match any unicode characters. In the regexes in this
-                block, negation is used specifically to match the end of an 
html
-                tag, and in fact unicode characters *should* be allowed.
-            */
-            var i, elList, workEl,
-                el = this.getSelectionElement(),
-                multiline = /<p|<br|<div/.test(text),
-                replacements = [
-
-                    // replace two bogus tags that begin pastes from google 
docs
-                    [new RegExp(/<[^>]*docs-internal-guid[^>]*>/gi), ""],
-                    [new RegExp(/<\/b>(<br[^>]*>)?$/gi), ""],
-
-                     // un-html spaces and newlines inserted by OS X
-                    [new RegExp(/<span 
class="Apple-converted-space">\s+<\/span>/g), ' '],
-                    [new RegExp(/<br class="Apple-interchange-newline">/g), 
'<br>'],
-
-                    // replace google docs italics+bold with a span to be 
replaced once the html is inserted
-                    [new 
RegExp(/<span[^>]*(font-style:italic;font-weight:bold|font-weight:bold;font-style:italic)[^>]*>/gi),
 '<span class="replace-with italic bold">'],
-
-                    // replace google docs italics with a span to be replaced 
once the html is inserted
-                    [new RegExp(/<span[^>]*font-style:italic[^>]*>/gi), '<span 
class="replace-with italic">'],
-
-                    //[replace google docs bolds with a span to be replaced 
once the html is inserted
-                    [new RegExp(/<span[^>]*font-weight:bold[^>]*>/gi), '<span 
class="replace-with bold">'],
-
-                     // replace manually entered b/i/a tags with real ones
-                    [new RegExp(/&lt;(\/?)(i|b|a)&gt;/gi), '<$1$2>'],
-
-                     // replace manually a tags with real ones, converting 
smart-quotes from google docs
-                    [new 
RegExp(/&lt;a\s+href=(&quot;|&rdquo;|&ldquo;|“|”)([^&]+)(&quot;|&rdquo;|&ldquo;|“|”)&gt;/gi),
 '<a href="$2">']
-
-                ];
-            /*jslint regexp: false*/
-
-            for (i = 0; i < replacements.length; i += 1) {
-                text = text.replace(replacements[i][0], replacements[i][1]);
-            }
-
-            if (multiline) {
-
-                // double br's aren't converted to p tags, but we want 
paragraphs.
-                elList = text.split('<br><br>');
-
-                this.pasteHTML('<p>' + elList.join('</p><p>') + '</p>');
-                document.execCommand('insertText', false, "\n");
-
-                // block element cleanup
-                elList = el.querySelectorAll('p,div,br');
-                for (i = 0; i < elList.length; i += 1) {
-
-                    workEl = elList[i];
-
-                    switch (workEl.tagName.toLowerCase()) {
-                    case 'p':
-                    case 'div':
-                        this.filterCommonBlocks(workEl);
-                        break;
-                    case 'br':
-                        this.filterLineBreak(workEl);
-                        break;
-                    }
-
-                }
-
-
-            } else {
-
-                this.pasteHTML(text);
-
-            }
-
-        },
-
-        pasteHTML: function (html) {
-            var elList, workEl, i, fragmentBody, pasteBlock = 
document.createDocumentFragment();
-
-            pasteBlock.appendChild(document.createElement('body'));
-
-            fragmentBody = pasteBlock.querySelector('body');
-            fragmentBody.innerHTML = html;
-
-            this.cleanupSpans(fragmentBody);
-
-            elList = fragmentBody.querySelectorAll('*');
-            for (i = 0; i < elList.length; i += 1) {
-
-                workEl = elList[i];
-
-                // delete ugly attributes
-                workEl.removeAttribute('class');
-                workEl.removeAttribute('style');
-                workEl.removeAttribute('dir');
-
-                if (workEl.tagName.toLowerCase() === 'meta') {
-                    workEl.parentNode.removeChild(workEl);
-                }
-
-            }
-            document.execCommand('insertHTML', false, 
fragmentBody.innerHTML.replace(/&nbsp;/g, ' '));
-        },
-        isCommonBlock: function (el) {
-            return (el && (el.tagName.toLowerCase() === 'p' || 
el.tagName.toLowerCase() === 'div'));
-        },
-        filterCommonBlocks: function (el) {
-            if (/^\s*$/.test(el.innerText)) {
-                el.parentNode.removeChild(el);
-            }
-        },
-        filterLineBreak: function (el) {
-            if (this.isCommonBlock(el.previousElementSibling)) {
-
-                // remove stray br's following common block elements
-                el.parentNode.removeChild(el);
-
-            } else if (this.isCommonBlock(el.parentNode) && 
(el.parentNode.firstChild === el || el.parentNode.lastChild === el)) {
-
-                // remove br's just inside open or close tags of a div/p
-                el.parentNode.removeChild(el);
-
-            } else if (el.parentNode.childElementCount === 1) {
-
-                // and br's that are the only child of a div/p
-                this.removeWithParent(el);
-
-            }
-
-        },
-
-        // remove an element, including its parent, if it is the only element 
within its parent
-        removeWithParent: function (el) {
-            if (el && el.parentNode) {
-                if (el.parentNode.parentNode && 
el.parentNode.childElementCount === 1) {
-                    el.parentNode.parentNode.removeChild(el.parentNode);
-                } else {
-                    el.parentNode.removeChild(el.parentNode);
-                }
-            }
-        },
-
-        cleanupSpans: function (container_el) {
-
-            var i,
-                el,
-                new_el,
-                spans = container_el.querySelectorAll('.replace-with');
-
-            for (i = 0; i < spans.length; i += 1) {
-
-                el = spans[i];
-                new_el = document.createElement(el.classList.contains('bold') 
? 'b' : 'i');
-
-                if (el.classList.contains('bold') && 
el.classList.contains('italic')) {
-
-                    // add an i tag as well if this has both italics and bold
-                    new_el.innerHTML = '<i>' + el.innerHTML + '</i>';
-
-                } else {
-
-                    new_el.innerHTML = el.innerHTML;
-
-                }
-                el.parentNode.replaceChild(new_el, el);
-
-            }
-
-            spans = container_el.querySelectorAll('span');
-            for (i = 0; i < spans.length; i += 1) {
-
-                el = spans[i];
-
-                // remove empty spans, replace others with their contents
-                if (/^\s*$/.test()) {
-                    el.parentNode.removeChild(el);
-                } else {
-                    
el.parentNode.replaceChild(document.createTextNode(el.innerText), el);
-                }
-
-            }
-
-        }
-
-    };
-
-}(window, document));
diff --git a/modules/editor/medium/theme/agora.css 
b/modules/editor/medium/theme/agora.css
deleted file mode 100644
index 705225b..0000000
--- a/modules/editor/medium/theme/agora.css
+++ /dev/null
@@ -1,128 +0,0 @@
-.medium-toolbar-arrow-under:after {
-       top: 45px;
-       border-color: #ffffff transparent transparent transparent;
-}
-
-.medium-toolbar-arrow-under:before {
-       top: 48px;
-       border-color: #cccccc transparent transparent transparent;
-       position: absolute;
-       left: 50%;
-       display: block;
-       margin-left: -8px;
-       width: 0;
-       height: 0;
-       border-style: solid;
-       content: "";
-       border-width: 8px 8px 0 8px;
-}
-
-.medium-toolbar-arrow-over:before {
-       border-color: transparent transparent #cccccc transparent;
-}
-
-.medium-toolbar-arrow-over:after {
-       top: -2px;
-       border-color: transparent transparent #ffffff transparent;
-       position: absolute;
-       left: 50%;
-       display: block;
-       margin-left: -8px;
-       width: 0;
-       height: 0;
-       border-style: solid;
-       content: "";
-       top: -6px;
-       border-width: 0 8px 8px 8px;
-}
-
-.medium-editor-toolbar {
-       border: 1px solid #cccccc;
-       background-color: #ffffff;
-       border-radius: 3px;
-       box-shadow: 0 2px 0 #cccccc;
-       transition: top .075s ease-out,left .075s ease-out;
-}
-
-.medium-editor-toolbar li button {
-       min-width: 45px;
-       height: 45px;
-       border: none;
-       border-right: 1px solid #fbfbfb;
-       background-color: transparent;
-       color: #555555;
-       box-sizing: border-box;
-       transition: background-color .2s ease-in, color .2s ease-in;
-}
-
-.medium-editor-toolbar li button:hover {
-       color: #333;
-       background: #fbfbfb;
-}
-
-.medium-editor-toolbar li .medium-editor-button-first {
-       border-top-left-radius: 3px;
-       border-bottom-left-radius: 3px;
-}
-
-.medium-editor-toolbar li .medium-editor-button-last {
-       border-right: none;
-       border-top-right-radius: 3px;
-       border-bottom-right-radius: 3px;
-}
-
-.medium-editor-toolbar li .medium-editor-button-active, .medium-editor-toolbar 
li .medium-editor-button-active:hover {
-       background-color: #f0f0f0;
-       color: #111111;
-  }
-
-.medium-editor-toolbar-form-anchor {
-       background: #ffffff;
-       color: #333;
-       border-radius: 3px;
-
-}
-
-.medium-editor-toolbar-form-anchor input {
-       height: 45px;
-       background: #ffffff;
-       color: #222222;
-}
-
-.medium-editor-toolbar-form-anchor input::-webkit-input-placeholder {
-       color: #888888;
-}
-
-.medium-editor-toolbar-form-anchor input:-moz-placeholder {
-       /* Firefox 18- */
-       color: #888888;
-}
-
-.medium-editor-toolbar-form-anchor input::-moz-placeholder {
-       /* Firefox 19+ */
-       color: #888888;
-}
-
-.medium-editor-toolbar-form-anchor input:-ms-input-placeholder {
-       color: #888888;
-}
-
-.medium-editor-toolbar-form-anchor a {
-       color: #222222;
-}
-
-.medium-editor-toolbar-anchor-preview {
-       background: #eeeeee;
-       color: #222222;
-       border-radius: 3px;
-       font-size: 0.8em;
-}
-
-.medium-editor-anchor-preview.medium-toolbar-arrow-over:before {
-       border-color: transparent transparent #eeeeee transparent;
-}
-
-.medium-editor-anchor-preview.medium-toolbar-arrow-over:after {
-       display:none;
-}
-
diff --git a/modules/tools/ext.cx.tools.formatter.js 
b/modules/tools/ext.cx.tools.formatter.js
new file mode 100644
index 0000000..8e1a1c7
--- /dev/null
+++ b/modules/tools/ext.cx.tools.formatter.js
@@ -0,0 +1,162 @@
+/**
+ * ContentTranslation Tools
+ * A tool that allows editors to translate pages from one language
+ * to another with the help of machine translation and other translation tools
+ *
+ * @file
+ * @ingroup Extensions
+ * @copyright See AUTHORS.txt
+ * @license GPL-2.0+
+ */
+( function ( $, mw ) {
+       'use strict';
+
+       var template = '<div class="card formatter">' +
+               '<span class="card__format-bold"></span>' +
+               '<span class="card__format-italics"></span>' +
+               '<span class="card__format-orderedlist"></span>' +
+               '<span class="card__format-bulletlist"></span>' +
+               '</div>';
+
+       /**
+        * Save the selection while other screen elements are clicked.
+        * See http://stackoverflow.com/a/3316483/337907
+        */
+       function saveSelection() {
+               var sel;
+
+               if ( window.getSelection ) {
+                       sel = window.getSelection();
+                       if ( sel.getRangeAt && sel.rangeCount ) {
+                               return sel.getRangeAt( 0 );
+                       }
+               } else if ( document.selection && 
document.selection.createRange ) {
+                       return document.selection.createRange();
+               }
+               return null;
+       }
+
+       /**
+        * Restore a saved selection
+        * See http://stackoverflow.com/a/3316483/337907
+        */
+       function restoreSelection( range ) {
+               var sel;
+
+               if ( range ) {
+                       if ( window.getSelection ) {
+                               sel = window.getSelection();
+                               sel.removeAllRanges();
+                               sel.addRange( range );
+                       } else if ( document.selection && range.select ) {
+                               range.select();
+                       }
+               }
+       }
+
+       /**
+        * Returns the parent node of the current selection as jQuery object
+        * @return {jQuery}
+        */
+       function getSelectionParent() {
+               var parent, selection;
+
+               if ( window.getSelection ) {
+                       selection = window.getSelection();
+                       if ( selection.rangeCount ) {
+                               parent = selection.getRangeAt( 0 
).commonAncestorContainer;
+                               if ( parent.nodeType !== 1 ) {
+                                       parent = parent.parentNode;
+                               }
+                       }
+               } else if ( document.selection ) {
+                       selection = document.selection;
+                       if ( selection.type !== 'Control' ) {
+                               parent = 
selection.createRange().parentElement();
+                       }
+               }
+
+               return $( parent );
+       }
+
+       function getParentSection() {
+               var $selectionParent = getSelectionParent();
+               if ( $selectionParent.is( '[contenteditable="true"]' ) ) {
+                       return $selectionParent;
+               }
+               return $selectionParent.parents( '[contenteditable="true"]' );
+       }
+
+       function FormatTool() {
+               this.$card = $( template );
+               this.$section = null;
+               this.buttons = {};
+               this.selection = null;
+               this.render();
+       }
+
+       FormatTool.prototype.render = function () {
+               this.buttons = {
+                       bold: this.$card.find( '.card__format-bold' ),
+                       italics: this.$card.find( '.card__format-italics' ),
+                       orderedlist: this.$card.find( 
'.card__format-orderedlist' ),
+                       bulletlist: this.$card.find( '.card__format-bulletlist' 
),
+               };
+               this.$card.hide();
+       };
+
+       FormatTool.prototype.onShow = function () {
+               mw.hook( 'mw.cx.tools.shown' ).fire( true );
+       };
+
+       FormatTool.prototype.getCard = function () {
+               return this.$card;
+       };
+
+       FormatTool.prototype.listen = function () {
+               var formatter = this;
+               this.buttons.bold.on( 'click', function () {
+                       restoreSelection( formatter.selection );
+                       document.execCommand( 'bold', false, null );
+               } );
+               this.buttons.italics.on( 'click', function () {
+                       restoreSelection( formatter.selection );
+                       document.execCommand( 'italic', false, null );
+               } );
+               this.buttons.orderedlist.on( 'click', function () {
+                       restoreSelection( formatter.selection );
+                       document.execCommand( 'insertOrderedList', false, null 
);
+               } );
+               this.buttons.bulletlist.on( 'click', function () {
+                       restoreSelection( formatter.selection );
+                       document.execCommand( 'insertUnorderedList', false, 
null );
+               } );
+       };
+
+       FormatTool.prototype.start = function ( section ) {
+               this.$section = section.jquery ? section : getParentSection();
+               if ( !this.$section || !this.$section.length ) {
+                       return;
+               }
+               // Capture the selection
+               this.selection = saveSelection();
+               this.listen();
+               this.$card.show();
+               this.onShow();
+       };
+
+       FormatTool.prototype.stop = function () {
+               this.$card.remove();
+               mw.hook( 'mw.cx.tools.shown' ).fire( false );
+       };
+
+       FormatTool.prototype.getTriggerEvents = function () {
+               return [
+                       'mw.cx.translation.focus',
+                       'mw.cx.select.word',
+                       'mw.cx.progress'
+               ];
+       };
+
+       mw.cx.tools.formatter = FormatTool;
+}( jQuery, mediaWiki ) );
diff --git a/modules/tools/images/bold-b.svg b/modules/tools/images/bold-b.svg
new file mode 100644
index 0000000..457b572
--- /dev/null
+++ b/modules/tools/images/bold-b.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg"; width="24" height="24" viewBox="0 0 24 
24">
+    <g id="bold-b" opacity=".75">
+        <path id="b" d="M7 18h6c2 0 4-1 4-3 0-1.064.011-1.975-1.989-3 2-.975 
1.989-1.935 1.989-3 0-2-2-3-4-3h-6v12zm7-8c0 1.001 0 1-2 1h-2v-3h2c2 0 2 0 2 
1v1zm-2 6h-2v-3h2c2 0 2 0 2 1v1s0 1-2 1z"/>
+    </g>
+</svg>
diff --git a/modules/tools/images/bullet-list-ltr.svg 
b/modules/tools/images/bullet-list-ltr.svg
new file mode 100644
index 0000000..316882a
--- /dev/null
+++ b/modules/tools/images/bullet-list-ltr.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg"; width="24" height="24" viewBox="0 0 24 
24">
+    <g id="bullet-list-ltr" opacity=".75">
+        <path id="bottom_dot" d="M5 10h-1c-.552 0-1 .447-1 1v1c0 .553.448 1 1 
1h1c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
+        <path id="middle_dot" d="M5 17h-1c-.552 0-1 .447-1 1v1c0 .553.448 1 1 
1h1c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
+        <path id="top_dot" d="M5 3h-1c-.552 0-1 .447-1 1v1c0 .553.448 1 1 
1h1c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
+        <path id="bottom_line" d="M20 17h-11c-.552 0-1 .447-1 1v1c0 .553.448 1 
1 1h11c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
+        <path id="middle_line" d="M20 10h-11c-.552 0-1 .447-1 1v1c0 .553.448 1 
1 1h11c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
+        <path id="top_line" d="M20 3h-11c-.552 0-1 .447-1 1v1c0 .553.448 1 1 
1h11c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
+    </g>
+</svg>
diff --git a/modules/tools/images/bullet-list-rtl.svg 
b/modules/tools/images/bullet-list-rtl.svg
new file mode 100644
index 0000000..34057ac
--- /dev/null
+++ b/modules/tools/images/bullet-list-rtl.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg"; width="24" height="24" viewBox="0 0 24 
24">
+    <g id="bullet-list-rtl" opacity=".75">
+        <path id="bottom_dot_1_" d="M19 10h1c.552 0 1 .447 1 1v1c0 .553-.448 
1-1 1h-1c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
+        <path id="middle_dot_1_" d="M19 17h1c.552 0 1 .447 1 1v1c0 .553-.448 
1-1 1h-1c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
+        <path id="top_dot_1_" d="M19 3h1c.552 0 1 .447 1 1v1c0 .553-.448 1-1 
1h-1c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
+        <path id="bottom_line_7_" d="M4 17h11c.552 0 1 .447 1 1v1c0 .553-.448 
1-1 1h-11c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
+        <path id="middle_line_7_" d="M4 10h11c.552 0 1 .447 1 1v1c0 .553-.448 
1-1 1h-11c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
+        <path id="top_line_7_" d="M4 3h11c.552 0 1 .447 1 1v1c0 .553-.448 1-1 
1h-11c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
+    </g>
+</svg>
diff --git a/modules/tools/images/italic-i.svg 
b/modules/tools/images/italic-i.svg
new file mode 100644
index 0000000..7af7b96
--- /dev/null
+++ b/modules/tools/images/italic-i.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg"; width="24" height="24" viewBox="0 0 24 
24">
+    <g id="italic-i" opacity=".75">
+        <path id="i" d="M12.5 
17.999l.249-.994h-1.5l2.509-10.037h1.5l.242-.967h-5l-.242.967h1.5l-2.509 
10.037h-1.5l-.249.994z"/>
+    </g>
+</svg>
diff --git a/modules/tools/images/number-list-ltr.svg 
b/modules/tools/images/number-list-ltr.svg
new file mode 100644
index 0000000..f4ce7d3
--- /dev/null
+++ b/modules/tools/images/number-list-ltr.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg"; width="24" height="24" viewBox="0 0 24 
24">
+    <g id="number-list-ltr" opacity=".75">
+        <path id="bottom_dot" d="M3 16v1h1.993l.03 
1h-1.023v1h1v1h-2v1h2.023l.977-1.002v-1l-.955-.531.955-.5v-.969l-1.007-.998z"/>
+        <path id="middle_dot" d="M3 9v1h2.117l-2.117 
2.187v1.811l3-.062v-.936h-2.118l2.118-2.188v-1.032l-.668-.78z"/>
+        <path id="top_dot" d="M4.993 2h-.648l-1.327 1.391.031.609h1.025l-.068 
2h-1.006v1h3v-1h-1.037z"/>
+        <path id="bottom_line" d="M20.002 17h-11.002c-.553 0-1 .447-1 1v1c0 
.553.447 1 1 1h11.002c.551 0 .998-.447.998-1v-1c0-.553-.447-1-.998-1z"/>
+        <path id="middle_line" d="M20.002 10h-11.002c-.553 0-1 .447-1 1v1c0 
.553.447 1 1 1h11.002c.551 0 .998-.447.998-1v-1c0-.553-.447-1-.998-1z"/>
+        <path id="top_line" d="M20.002 3h-11.002c-.553 0-1 .447-1 1v1c0 
.553.447 1 1 1h11.002c.551 0 .998-.447.998-1v-1c0-.553-.447-1-.998-1z"/>
+    </g>
+</svg>
diff --git a/modules/tools/images/number-list-rtl.svg 
b/modules/tools/images/number-list-rtl.svg
new file mode 100644
index 0000000..b0328a9
--- /dev/null
+++ b/modules/tools/images/number-list-rtl.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg"; width="24" height="24" viewBox="0 0 24 
24">
+    <g id="number-list-rtl" opacity=".75">
+        <path id="bottom_dot" d="M18 16v1h1.993l.03 
1h-1.023v1h1v1h-2v1h2.023l.977-1.002v-1l-.956-.531.956-.5v-.969l-1.007-.998z"/>
+        <path id="middle_dot" d="M18 9v1h2.116l-2.116 
2.187v1.811l3-.062v-.936h-2.118l2.118-2.188v-1.032l-.669-.78z"/>
+        <path id="top_dot" d="M19.993 2h-.648l-1.328 1.391.031.609h1.026l-.069 
2h-1.005v1h3v-1h-1.038z"/>
+        <path id="bottom_line" d="M3.999 17h11.002c.552 0 .999.447.999 1v1c0 
.553-.447 1-.999 1h-11.002c-.552 0-.999-.447-.999-1v-1c0-.553.447-1 .999-1z"/>
+        <path id="middle_line" d="M3.999 10h11.002c.552 0 .999.447.999 1v1c0 
.553-.447 1-.999 1h-11.002c-.552 0-.999-.447-.999-1v-1c0-.553.447-1 .999-1z"/>
+        <path id="top_line" d="M3.999 3h11.002c.552 0 .999.447.999 1v1c0 
.553-.447 1-.999 1h-11.002c-.552 0-.999-.447-.999-1v-1c0-.553.447-1 .999-1z"/>
+    </g>
+</svg>
diff --git a/modules/tools/styles/ext.cx.tools.formatter.less 
b/modules/tools/styles/ext.cx.tools.formatter.less
new file mode 100644
index 0000000..babfd94
--- /dev/null
+++ b/modules/tools/styles/ext.cx.tools.formatter.less
@@ -0,0 +1,48 @@
+@import "../../base/styles/grid/agora-grid";
+@import "mediawiki.mixins";
+
+.card.formatter {
+       animation-name: card-show-animation;
+       animation-duration: 0.5s;
+       position: relative;
+       min-height: 45px;
+}
+
+.formatter-button {
+       min-width: 45px;
+       height: 45px;
+       border: none;
+       border-right: 1px solid #fbfbfb;
+       background-color: transparent;
+       color: #555555;
+       box-sizing: border-box;
+       float: left;
+       transition: background-color .2s ease-in, color .2s ease-in;
+       &:hover {
+               border: 1px solid #eee;
+       }
+}
+.card__format-bold {
+       .formatter-button;
+       .background-image-svg('../images/bold-b.svg','../images/bold-b.png');
+       background-repeat: no-repeat;
+       background-position: center;
+}
+.card__format-italics {
+       .formatter-button;
+       
.background-image-svg('../images/italic-i.svg','../images/italic-i.png');
+       background-repeat: no-repeat;
+       background-position: center;
+}
+.card__format-orderedlist {
+       .formatter-button;
+       .background-image-svg('../images/number-list-ltr.svg', 
'../images/number-list-ltr.png');
+       background-repeat: no-repeat;
+       background-position: center;
+}
+.card__format-bulletlist {
+       .formatter-button;
+       .background-image-svg('../images/bullet-list-ltr.svg', 
'../images/bullet-list-ltr.png');
+       background-repeat: no-repeat;
+       background-position: center;
+}
diff --git a/specials/SpecialContentTranslation.php 
b/specials/SpecialContentTranslation.php
index 53c6030..961912f 100644
--- a/specials/SpecialContentTranslation.php
+++ b/specials/SpecialContentTranslation.php
@@ -22,21 +22,11 @@
        }
 
        public function execute( $parameters ) {
-               global $wgContentTranslationExperimentalFeatures;
-
                $out = $this->getOutput();
                $skin = $this->getSkin();
 
                $out->addModuleStyles( 'mediawiki.ui.button' );
                $out->addModules( 'ext.cx.base' );
-               if ( $wgContentTranslationExperimentalFeatures ) {
-                       // WYSIWYGEditor
-                       $out->addModules( 'ext.cx.editor.medium' );
-               } else {
-                       // Just ContentEditable
-                       $out->addModules( 'ext.cx.editor' );
-               }
-
                $this->setHeaders();
                $out->setArticleBodyOnly( true );
 

-- 
To view, visit https://gerrit.wikimedia.org/r/158369
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I794d7e6bfcd3792acea6cae6ec00492251018ba7
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/ContentTranslation
Gerrit-Branch: master
Gerrit-Owner: Santhosh <santhosh.thottin...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to