diff --git a/README.md b/README.md index 1364091..24af457 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Demo ``` $ git clone https://github.com/TerryMooreII/angular-wysiwyg.git -$ npm install +$ npm install $ gulp server ``` Open browser to http://localhost:4000/demo @@ -28,7 +28,7 @@ Installation Required dependancies ----------------------- -* [AngularJS] (http://www.angularjs.com) +* [AngularJS] (http://www.angularjs.com) * [Font Awesome] (http://fortawesome.github.io/Font-Awesome/) * [Twitter Bootstrap] (http://getbootstrap.com/2.3.2/) * [bootstrap-color-picker] (https://github.com/buberdds/angular-bootstrap-colorpicker) @@ -52,14 +52,14 @@ Options Option|Description ---------------------|--------------- **ng-model** | REQUIRED - The angular data model -**textarea-id** | The id to assign to the editable div +**textarea-id** | REQUIRED (If using videos) - The id to assign to the editable div **textarea-class** | The class(es) to assign to the the editable div **textarea-height** | If the height is not specified in a text-area class then the hight of the editable div (default: 80px) -**textarea-name** | The name attribute of the editable div +**textarea-name** | The name attribute of the editable div **textarea-required**| True/False HTML/AngularJS required validation -**enable-bootstrap-title**| True/False whether or not to show the button hover title styled with bootstrap +**enable-bootstrap-title**| True/False whether or not to show the button hover title styled with bootstrap **textarea-menu** | Cusomize the wysiwyg buttons and button groups ***See Below** If nothing is specified then the default buttons and groups will be shown. -**disabled** | Disable the buttons and wysiwig area +**disabled** | Disable the buttons and wysiwig area Buttons -------------- @@ -69,7 +69,7 @@ If you don't need all of the buttons and functions of the default WYSIWYG editor To do so you need to create a scope variable in your controller. This variable be an array that contains arrays of button groups. ```javascript - + //This also happens to be the default menu options. $scope.yourModel.customMenu = [ ['bold', 'italic', 'underline', 'strikethrough', 'subscript', 'superscript'], @@ -81,25 +81,25 @@ To do so you need to create a scope variable in your controller. This variable ['ordered-list', 'unordered-list', 'outdent', 'indent'], ['left-justify', 'center-justify', 'right-justify'], ['code', 'quote', 'paragraph'], - ['link', 'image'] + ['link', 'image', 'video'] ]; ``` -So above each array will end up being a group of the specified buttons. +So above each array will end up being a group of the specified buttons. **Note:** The `font` and `font-size` dropdowns must be in thier own group. -List of possible buttons | -------------| +List of possible buttons | Notes +------------|-------------- bold | -italic | -underline | -strikethrough | +italic | +underline | +strikethrough | subscript | superscript | -font | +font | font-size | -font-color | +font-color | hilite-color | remove-format | ordered-list | @@ -114,8 +114,4 @@ paragraph | quote | link | image | - - - - - +video | Converts youtube and vimeo links to imbedded ones diff --git a/demo/index.html b/demo/index.html index 6b47fdb..84db74a 100644 --- a/demo/index.html +++ b/demo/index.html @@ -1,6 +1,6 @@ - + @@ -21,25 +21,26 @@

Angular WYSIWYG directive

-
-
-

Your models data

-

- {{data.text}} -

- - - -
-
+
+
+

Your models data

+

+ {{data.text}} +

+ + + +
+
- \ No newline at end of file + diff --git a/demo/scripts/app.js b/demo/scripts/app.js index 51921b7..5c62c42 100644 --- a/demo/scripts/app.js +++ b/demo/scripts/app.js @@ -1,9 +1,9 @@ -var app = angular.module('app', ['colorpicker.module', 'wysiwyg.module']) +var app = angular.module('app', ['colorpicker.module', 'wysiwyg.module']); app.controller('MyCtrl', function($scope) { $scope.data = { text: "hello" - } + }; $scope.disabled = false; $scope.menu = [ ['bold', 'italic', 'underline', 'strikethrough', 'subscript', 'superscript'], @@ -15,7 +15,7 @@ app.controller('MyCtrl', function($scope) { ['ordered-list', 'unordered-list', 'outdent', 'indent'], ['left-justify', 'center-justify', 'right-justify'], ['code', 'quote', 'paragraph'], - ['link', 'image'], + ['link', 'image', 'video'], ['css-class'] ]; @@ -23,5 +23,5 @@ app.controller('MyCtrl', function($scope) { $scope.setDisabled = function() { $scope.disabled = !$scope.disabled; - } -}) \ No newline at end of file + }; +}); diff --git a/dist/angular-wysiwyg.js b/dist/angular-wysiwyg.js index 7fbde5e..1888b5a 100644 --- a/dist/angular-wysiwyg.js +++ b/dist/angular-wysiwyg.js @@ -4,24 +4,24 @@ Usage: ' }, { name: 'Heading 1', - value: 'h1' + value: '

' }, { name: 'Heading 2', - value: 'h2' + value: '

' }, { name: 'Heading 3', - value: 'h3' + value: '

' }, { name: 'Heading 4', - value: 'h4' + value: '

' }, { name: 'Heading 5', - value: 'h5' + value: '

' }, { name: 'Heading 6', - value: 'h6' + value: '
' } ]; scope.formatBlock = scope.formatBlocks[0]; @@ -206,7 +207,12 @@ Requires: function insertTab(html, position) { var begining = html.substr(0, position); var end = html.substr(position); - return begining + ' ' + end; + var TAB_SPACES = 4; + var space; + for (var i = 0; i < TAB_SPACES; i++) { + space += ' '; + } + return begining + '' + space + '' + end; } function configureListeners() { //Send message to calling controller that a button has been clicked. @@ -216,20 +222,20 @@ Requires: }); textarea.on('input keyup paste mouseup', function () { var html = textarea.html(); - if (html == '
') { + if (html === '
') { html = ''; } ngModelController.$setViewValue(html); }); textarea.on('keydown', function (event) { - if (event.keyCode == 9) { + if (event.keyCode === 9) { var TAB_SPACES = 4; var html = textarea.html(); var selection = window.getSelection(); var position = selection.anchorOffset; event.preventDefault(); // html = insertTab(html, position); // textarea.html(html); - // selection.collapse(textarea[0].firstChild, position + TAB_SPACES); + // selection.collapse(textarea[0].firstChild, position + TAB_SPACES); } }); textarea.on('click keyup focus mouseup', function () { @@ -241,7 +247,7 @@ Requires: scope.isSuperscript = itemIs('SUP'); //scope.cmdState('superscript'); scope.isSubscript = itemIs('SUB'); - //scope.cmdState('subscript'); + //scope.cmdState('subscript'); scope.isRightJustified = scope.cmdState('justifyright'); scope.isLeftJustified = scope.cmdState('justifyleft'); scope.isCenterJustified = scope.cmdState('justifycenter'); @@ -313,7 +319,7 @@ Requires: textarea.html(ngModelController.$viewValue); }; scope.format = function (cmd, arg) { - document.execCommand(cmd, false, arg); + document.execCommand(cmd, true, arg); }; scope.cmdState = function (cmd) { return document.queryCommandState(cmd); @@ -331,6 +337,38 @@ Requires: if (input && input !== undefined) scope.format('insertimage', input); }; + //Finds the parent of a node with the specified id, or returns null + function findParent(node, id) { + if (node === null) + return null; + if (node.id === id) + return node; + return findParent(node.parentNode, id); + } + scope.insertVideo = function () { + var sel = document.getSelection(); + if (sel.rangeCount <= 0) { + console.log('No range selected'); + return; + } + var input = prompt('Enter the video URL'); + if (input && input !== undefined) { + //Convertion of normal youtube and vimeo linkt into imbed links + var match; + if ((match = /youtube\.com\/watch\?v=(.*)/.exec(input)) !== null) { + input = 'https://www.youtube.com/embed/' + match[1]; + } else if ((match = /[^player]\/vimeo\.com\/(.*)/.exec(input)) !== null) { + input = 'https://player.vimeo.com/video/' + match[1]; + } + var videoElement = ''; + var range = sel.getRangeAt(0); + //Prevent user from addin videos outside of the element + if (findParent(range.startContainer, scope.textareaId) === null) + return; + var nnode = range.createContextualFragment(videoElement); + range.insertNode(nnode); + } + }; scope.setFont = function () { scope.format('fontname', scope.font); }; @@ -380,6 +418,7 @@ Requires: var el; for (var i = 0; i < menu.length; i++) { var menuGroup = create(getMenuGroup()); + //console.log(menuGroup); for (var j = 0; j < menu[i].length; j++) { //link has two functions link and unlink if (menu[i][j] === 'link') { @@ -406,7 +445,7 @@ Requires: } if (obj.text && document.all) { el.innerText = obj.text; - } else { + } else if (obj.text) { el.textContent = obj.text; } if (obj.classes) { @@ -885,6 +924,28 @@ Requires: classes: 'fa fa-picture-o' }] }, + 'video': { + tag: 'button', + classes: 'btn btn-default', + attributes: [ + { + name: 'title', + value: 'Video' + }, + { + name: 'ng-click', + value: 'insertVideo()' + }, + { + name: 'type', + value: 'button' + } + ], + data: [{ + tag: 'i', + classes: 'fa fa-youtube-play' + }] + }, 'font-color': { tag: 'button', classes: 'btn btn-default wysiwyg-colorpicker wysiwyg-fontcolor', diff --git a/dist/angular-wysiwyg.min.js b/dist/angular-wysiwyg.min.js index 1e94c44..10542b6 100644 --- a/dist/angular-wysiwyg.min.js +++ b/dist/angular-wysiwyg.min.js @@ -1 +1 @@ -!function(t,e){"use strict";var a=[["bold","italic","underline","strikethrough","subscript","superscript"],["format-block"],["font"],["font-size"],["font-color","hilite-color"],["remove-format"],["ordered-list","unordered-list","outdent","indent"],["left-justify","center-justify","right-justify"],["code","quote","paragraph"],["link","image"]];t.module("wysiwyg.module",["colorpicker.module"]).directive("wysiwyg",["$timeout","wysiwgGui","$compile",function(a,n,i){function l(l,s,o,r){function u(){c(),m(),f(),d()}function c(){n.setCustomElements(l.textareaCustomMenu);var t=s.children("div.wysiwyg-menu")[0];t.appendChild(n.createMenu(l.textareaMenu)),i(t)(l)}function m(){l.$watch("disabled",function(e){t.element("div.wysiwyg-menu").find("button").each(function(){t.element(this).attr("disabled",e)}),t.element("div.wysiwyg-menu").find("select").each(function(){t.element(this).attr("disabled",e)})})}function f(){"true"===o.enableBootstrapTitle&&o.enableBootstrapTitle!==e&&s.find("button[title]").tooltip({container:"body"})}function d(){t.element(".wysiwyg-menu").find("button").on("click",function(){var e=t.element(this);l.$emit("wysiwyg.click",e.attr("title")||e.attr("data-original-title"))}),b.on("input keyup paste mouseup",function(){var t=b.html();"
"==t&&(t=""),r.$setViewValue(t)}),b.on("keydown",function(t){if(9==t.keyCode){{var e=(b.html(),window.getSelection());e.anchorOffset}t.preventDefault()}}),b.on("click keyup focus mouseup",function(){a(function(){l.isBold=l.cmdState("bold"),l.isUnderlined=l.cmdState("underline"),l.isStrikethrough=l.cmdState("strikethrough"),l.isItalic=l.cmdState("italic"),l.isSuperscript=g("SUP"),l.isSubscript=g("SUB"),l.isRightJustified=l.cmdState("justifyright"),l.isLeftJustified=l.cmdState("justifyleft"),l.isCenterJustified=l.cmdState("justifycenter"),l.isPre="pre"===l.cmdValue("formatblock"),l.isBlockquote="blockquote"===l.cmdValue("formatblock"),l.isOrderedList=l.cmdState("insertorderedlist"),l.isUnorderedList=l.cmdState("insertunorderedlist"),l.fonts.forEach(function(t){return l.cmdValue("fontname").indexOf(t)>-1?(l.font=t,!1):void 0}),l.cmdValue("formatblock").toLowerCase(),l.formatBlocks.forEach(function(t){return l.cmdValue("formatblock").toLowerCase()===t.value.toLowerCase()?(l.formatBlock=t,!1):void 0}),l.fontSizes.forEach(function(t){return l.cmdValue("fontsize")===t.value?(l.fontSize=t,!1):void 0}),l.hiliteColor=v(),s.find("button.wysiwyg-hiliteColor").css("background-color",l.hiliteColor),l.fontColor=l.cmdValue("forecolor"),s.find("button.wysiwyg-fontcolor").css("color",l.fontColor),l.isLink=g("A")},0)})}function g(t){var e=window.getSelection().getRangeAt(0);return e&&(e.startContainer.parentNode.tagName===t.toUpperCase()||e.endContainer.parentNode.tagName===t.toUpperCase())?!0:!1}function v(){var e=window.getSelection().getRangeAt(0);if(e){var a=t.element(e.startContainer.parentNode).attr("style");if(!t.isDefined(a))return!1;for(var n=a.split(";"),i=0;i
',restrict:"E",scope:{value:"=ngModel",textareaHeight:"@textareaHeight",textareaName:"@textareaName",textareaClass:"@textareaClass",textareaRequired:"@textareaRequired",textareaId:"@textareaId",textareaMenu:"=textareaMenu",textareaCustomMenu:"=textareaCustomMenu",fn:"&",disabled:"=?disabled"},replace:!0,require:"ngModel",link:l,transclude:!0}}]).factory("wysiwgGui",["wysiwgGuiElements",function(e){function n(t){var e;if(t.tag)e=document.createElement(t.tag);else{if(!t.text)return console.log("cannot create this element."),e=document.createElement("span");e=document.createElement("span")}if(t.text&&document.all?e.innerText=t.text:e.textContent=t.text,t.classes&&(e.className=t.classes),t.html&&(e.innerHTML=t.html),t.attributes&&t.attributes.length)for(var a in t.attributes){var i=t.attributes[a];i.name&&i.value&&e.setAttribute(i.name,i.value)}if(t.data&&t.data.length)for(var l in t.data)e.appendChild(n(t.data[l]));return e}var i=e,l={},s=function(t){l=t},o=function(){return{tag:"div",classes:"btn-group btn-group-sm wysiwyg-btn-group-margin"}},r=function(t){return i[t]||{}},u=function(e){t.extend(i,l),e=t.isDefined(e)&&""!==e?e:a;for(var s,u=document.createElement("div"),c=0;c"===e&&(e=""),r.$setViewValue(e)}),p.on("keydown",function(e){if(9===e.keyCode){{var t=(p.html(),window.getSelection());t.anchorOffset}e.preventDefault()}}),p.on("click keyup focus mouseup",function(){a(function(){l.isBold=l.cmdState("bold"),l.isUnderlined=l.cmdState("underline"),l.isStrikethrough=l.cmdState("strikethrough"),l.isItalic=l.cmdState("italic"),l.isSuperscript=g("SUP"),l.isSubscript=g("SUB"),l.isRightJustified=l.cmdState("justifyright"),l.isLeftJustified=l.cmdState("justifyleft"),l.isCenterJustified=l.cmdState("justifycenter"),l.isPre="pre"===l.cmdValue("formatblock"),l.isBlockquote="blockquote"===l.cmdValue("formatblock"),l.isOrderedList=l.cmdState("insertorderedlist"),l.isUnorderedList=l.cmdState("insertunorderedlist"),l.fonts.forEach(function(e){return l.cmdValue("fontname").indexOf(e)>-1?(l.font=e,!1):void 0}),l.cmdValue("formatblock").toLowerCase(),l.formatBlocks.forEach(function(e){return l.cmdValue("formatblock").toLowerCase()===e.value.toLowerCase()?(l.formatBlock=e,!1):void 0}),l.fontSizes.forEach(function(e){return l.cmdValue("fontsize")===e.value?(l.fontSize=e,!1):void 0}),l.hiliteColor=v(),o.find("button.wysiwyg-hiliteColor").css("background-color",l.hiliteColor),l.fontColor=l.cmdValue("forecolor"),o.find("button.wysiwyg-fontcolor").css("color",l.fontColor),l.isLink=g("A")},0)})}function g(e){var t=window.getSelection().getRangeAt(0);return t&&(t.startContainer.parentNode.tagName===e.toUpperCase()||t.endContainer.parentNode.tagName===e.toUpperCase())?!0:!1}function v(){var t=window.getSelection().getRangeAt(0);if(t){var a=e.element(t.startContainer.parentNode).attr("style");if(!e.isDefined(a))return!1;for(var n=a.split(";"),i=0;i"},{name:"Heading 1",value:"

"},{name:"Heading 2",value:"

"},{name:"Heading 3",value:"

"},{name:"Heading 4",value:"

"},{name:"Heading 5",value:"

"},{name:"Heading 6",value:"
"}],l.formatBlock=l.formatBlocks[0],l.fontSize=l.fontSizes[1],e.isArray(l.cssClasses)&&(l.cssClasses.unshift("css"),l.cssClass=l.cssClasses[0]),l.fonts=["Georgia","Palatino Linotype","Times New Roman","Arial","Helvetica","Arial Black","Comic Sans MS","Impact","Lucida Sans Unicode","Tahoma","Trebuchet MS","Verdana","Courier New","Lucida Console","Helvetica Neue"].sort(),l.font=l.fonts[6],u(),r.$render=function(){p.html(r.$viewValue)},l.format=function(e,t){document.execCommand(e,!0,t)},l.cmdState=function(e){return document.queryCommandState(e)},l.cmdValue=function(e){return document.queryCommandValue(e)},l.createLink=function(){var e=prompt("Enter the link URL");e&&e!==t&&l.format("createlink",e)},l.insertImage=function(){var e=prompt("Enter the image URL");e&&e!==t&&l.format("insertimage",e)},l.insertVideo=function(){var e=document.getSelection();if(e.rangeCount<=0)return void console.log("No range selected");var a=prompt("Enter the video URL");if(a&&a!==t){var n;null!==(n=/youtube\.com\/watch\?v=(.*)/.exec(a))?a="https://www.youtube.com/embed/"+n[1]:null!==(n=/[^player]\/vimeo\.com\/(.*)/.exec(a))&&(a="https://player.vimeo.com/video/"+n[1]);var i="",o=e.getRangeAt(0);if(null===b(o.startContainer,l.textareaId))return;var s=o.createContextualFragment(i);o.insertNode(s)}},l.setFont=function(){l.format("fontname",l.font)},l.setFontSize=function(){l.format("fontsize",l.fontSize.value)},l.setFormatBlock=function(){l.format("formatBlock",l.formatBlock.value)},l.setFontColor=function(){l.format("forecolor",l.fontColor)},l.setHiliteColor=function(){l.format("hiliteColor",l.hiliteColor)},l.format("enableobjectresizing",!0),l.format("styleWithCSS",!0)}return{template:'
',restrict:"E",scope:{value:"=ngModel",textareaHeight:"@textareaHeight",textareaName:"@textareaName",textareaClass:"@textareaClass",textareaRequired:"@textareaRequired",textareaId:"@textareaId",textareaMenu:"=textareaMenu",textareaCustomMenu:"=textareaCustomMenu",fn:"&",disabled:"=?disabled"},replace:!0,require:"ngModel",link:l,transclude:!0}}]).factory("wysiwgGui",["wysiwgGuiElements",function(t){function n(e){var t;if(e.tag)t=document.createElement(e.tag);else{if(!e.text)return console.log("cannot create this element."),t=document.createElement("span");t=document.createElement("span")}if(e.text&&document.all?t.innerText=e.text:e.text&&(t.textContent=e.text),e.classes&&(t.className=e.classes),e.html&&(t.innerHTML=e.html),e.attributes&&e.attributes.length)for(var a in e.attributes){var i=e.attributes[a];i.name&&i.value&&t.setAttribute(i.name,i.value)}if(e.data&&e.data.length)for(var l in e.data)t.appendChild(n(e.data[l]));return t}var i=t,l={},o=function(e){l=e},s=function(){return{tag:"div",classes:"btn-group btn-group-sm wysiwyg-btn-group-margin"}},r=function(e){return i[e]||{}},u=function(t){e.extend(i,l),t=e.isDefined(t)&&""!==t?t:a;for(var o,u=document.createElement("div"),c=0;c' }, { name: 'Heading 1', - value: 'h1' + value: '

' }, { name: 'Heading 2', - value: 'h2' + value: '

' }, { name: 'Heading 3', - value: 'h3' + value: '

' }, { name: 'Heading 4', - value: 'h4' + value: '

' }, { name: 'Heading 5', - value: 'h5' + value: '

' }, { name: 'Heading 6', - value: 'h6' + value: '
' }, ]; scope.formatBlock = scope.formatBlocks[0]; @@ -193,7 +193,10 @@ Requires: function insertTab(html, position) { var begining = html.substr(0, position); var end = html.substr(position); - return begining + ' ' + end; + var TAB_SPACES = 4; + var space; + for(var i = 0; i < TAB_SPACES; i++) {space += " ";} + return begining + ''+ space + '' + end; } function configureListeners() { @@ -207,24 +210,24 @@ Requires: textarea.on('input keyup paste mouseup', function() { var html = textarea.html(); - if (html == '
') { + if (html === '
') { html = ''; } ngModelController.$setViewValue(html); - }); + }); textarea.on('keydown', function(event){ - if (event.keyCode == 9){ + if (event.keyCode === 9){ var TAB_SPACES = 4; var html = textarea.html(); var selection = window.getSelection(); var position = selection.anchorOffset; - + event.preventDefault(); // html = insertTab(html, position); // textarea.html(html); - // selection.collapse(textarea[0].firstChild, position + TAB_SPACES); + // selection.collapse(textarea[0].firstChild, position + TAB_SPACES); } }); @@ -235,7 +238,7 @@ Requires: scope.isStrikethrough = scope.cmdState('strikethrough'); scope.isItalic = scope.cmdState('italic'); scope.isSuperscript = itemIs('SUP'); //scope.cmdState('superscript'); - scope.isSubscript = itemIs('SUB'); //scope.cmdState('subscript'); + scope.isSubscript = itemIs('SUB'); //scope.cmdState('subscript'); scope.isRightJustified = scope.cmdState('justifyright'); scope.isLeftJustified = scope.cmdState('justifyleft'); scope.isCenterJustified = scope.cmdState('justifycenter'); @@ -319,7 +322,7 @@ Requires: }; scope.format = function(cmd, arg) { - document.execCommand(cmd, false, arg); + document.execCommand(cmd, true, arg); }; scope.cmdState = function(cmd) { @@ -342,6 +345,41 @@ Requires: scope.format('insertimage', input); }; + //Finds the parent of a node with the specified id, or returns null + function findParent(node, id){ + if(node === null) return null; + if(node.id === id) return node; + return findParent(node.parentNode, id); + } + + scope.insertVideo = function() { + var sel = document.getSelection(); + if(sel.rangeCount <= 0) { console.log("No range selected"); return;} + + var input = prompt('Enter the video URL'); + if (input && input !== undefined) + { + //Convertion of normal youtube and vimeo linkt into imbed links + var match; + if((match = /youtube\.com\/watch\?v=(.*)/.exec(input)) !== null){ + input = 'https://www.youtube.com/embed/' + match[1]; + } + else if ((match = /[^player]\/vimeo\.com\/(.*)/.exec(input)) !== null) { + input = 'https://player.vimeo.com/video/' + match[1]; + } + + var videoElement = ''; + + var range = sel.getRangeAt(0); + + //Prevent user from addin videos outside of the element + if(findParent(range.startContainer, scope.textareaId) === null) return; + + var nnode = range.createContextualFragment(videoElement); + range.insertNode(nnode); + } + }; + scope.setFont = function() { scope.format('fontname', scope.font); }; @@ -387,7 +425,6 @@ Requires: }; var createMenu = function(menu) { - angular.extend(ELEMENTS, custom); //Get the default menu or the passed in menu @@ -400,9 +437,9 @@ Requires: //create div to add everything to. var startDiv = document.createElement('div'); var el; - for (var i = 0; i < menu.length; i++) { var menuGroup = create(getMenuGroup()); + //console.log(menuGroup); for (var j = 0; j < menu[i].length; j++) { //link has two functions link and unlink @@ -435,7 +472,7 @@ Requires: if (obj.text && document.all) { el.innerText = obj.text; - } else if (obj.text) { + } else if(obj.text){ el.textContent = obj.text; } @@ -835,6 +872,24 @@ Requires: classes: 'fa fa-picture-o' }] }, + 'video': { + tag: 'button', + classes: 'btn btn-default', + attributes: [{ + name: 'title', + value: 'Video' + }, { + name: 'ng-click', + value: 'insertVideo()' + }, { + name: 'type', + value: 'button' + }], + data: [{ + tag: 'i', + classes: 'fa fa-youtube-play' + }] + }, 'font-color': { tag: 'button', classes: 'btn btn-default wysiwyg-colorpicker wysiwyg-fontcolor',