diff --git a/README.md b/README.md index 1364091..a48d12e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - Angular WYSIWYG directive. =========================== @@ -58,7 +57,9 @@ Option|Description **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 -**textarea-menu** | Cusomize the wysiwyg buttons and button groups ***See Below** If nothing is specified then the default buttons and groups will be shown. +**textarea-menu** | Customize the wysiwyg buttons and button groups ***See Below** If nothing is specified then the default buttons and groups will be shows. +**textarea-custom-menu** | Create a customized menu +**textarea-custom-functions** | Allow add your custom function to your custom element **disabled** | Disable the buttons and wysiwig area Buttons @@ -115,7 +116,70 @@ quote | link | image | +Custom elements +-------------- +You can add you own button or select element - +````html + +``` +```javascript +var insertVariables = { + '0': 'Choose one', + 'a': 'Insert a', + 'b': 'Insert b' + }; + var insertOptions = []; + for (var i in insertVariables) { + insertOptions.push({ + tag: 'option', + attributes: [{ + name: 'value', + value: i + }], + text: insertVariables[i] + }); + } + $scope.yourModel = {}; + $scope.yourModel.customMenu = { + 'myInsertElement': { + tag: 'select', + classes: 'form-control wysiwyg-select', + attributes: [{ + name: 'ng-model', + value: 'myInsertElement' + }, { + name: 'ng-init', + value: 'myInsertElement = "0"' + }, { + name: 'ng-change', + value: 'chInsert(this)' + }], + data: insertOptions, + }, + }; + + $scope.yourModel.customFunctions = { + chInsert: function(scope) { + if (scope.myInsertElement != '0') { + document.execCommand("insertHTML", false, scope.myInsertElement); + scope.myInsertElement = '0'; + } + } + }; + $scope.yourModel.menu = [ + ['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'], + ['myInsertElement'] + ]; +``` diff --git a/bower.json b/bower.json index 8ed90a8..ae54a2d 100644 --- a/bower.json +++ b/bower.json @@ -8,6 +8,7 @@ "dependencies": { "angular": ">= 1.0.0", "angular-bootstrap-colorpicker": ">= 3.0.0", - "jquery": "~2.1.3" + "jquery": "~2.1.3", + "flickrapi": "0.3.36" } } diff --git a/demo/index.html b/demo/index.html index 6b47fdb..5dc1d99 100644 --- a/demo/index.html +++ b/demo/index.html @@ -16,6 +16,12 @@ .test1{ font-size:1.8em; } + + #question{ + font-family: Lucida Console; + font-size: 24px; + color: lightgrey; + } diff --git a/demo/scripts/app.js b/demo/scripts/app.js index 51921b7..3a06396 100644 --- a/demo/scripts/app.js +++ b/demo/scripts/app.js @@ -15,8 +15,7 @@ app.controller('MyCtrl', function($scope) { ['ordered-list', 'unordered-list', 'outdent', 'indent'], ['left-justify', 'center-justify', 'right-justify'], ['code', 'quote', 'paragraph'], - ['link', 'image'], - ['css-class'] + ['link', 'image'] ]; $scope.cssClasses = ['test1', 'test2']; diff --git a/dist/angular-wysiwyg.js b/dist/angular-wysiwyg.js index 09523f5..22b051b 100644 --- a/dist/angular-wysiwyg.js +++ b/dist/angular-wysiwyg.js @@ -4,24 +4,24 @@ Usage: ' + '' + '' + '' + '', + template: '' + '' + '' + '' + '', restrict: 'E', scope: { value: '=ngModel', @@ -81,7 +82,8 @@ Requires: textareaMenu: '=textareaMenu', textareaCustomMenu: '=textareaCustomMenu', fn: '&', - disabled: '=?disabledArea' + disabled: '=?disabled', + textareaCustomFunctions: '=textareaCustomFunctions' }, replace: true, require: 'ngModel', @@ -153,10 +155,6 @@ Requires: ]; scope.formatBlock = scope.formatBlocks[0]; scope.fontSize = scope.fontSizes[1]; - if (angular.isArray(scope.cssClasses)) { - scope.cssClasses.unshift('css'); - scope.cssClass = scope.cssClasses[0]; - } scope.fonts = [ 'Georgia', 'Palatino Linotype', @@ -177,18 +175,49 @@ Requires: scope.font = scope.fonts[6]; init(); function init() { + applyDefaultsFromStyle(); compileMenu(); - configureDisabledWatch(); + configureWatchers(); configureBootstrapTitle(); configureListeners(); } + function updateSelectedColorButton() { + element.find('button.wysiwyg-fontcolor').css('color', scope.fontColor); + } + function applyDefaultsFromStyle() { + $timeout(function () { + var textArea = element.find('.wysiwyg-textarea')[0]; + var styles = $window.getComputedStyle(textArea, null); + if (styles.fontFamily != null) { + var fontName = styles.fontFamily.split(',')[0]; + //Remove "'" symbols from style name + fontName = fontName.slice(1, -1); + if (scope.fonts.indexOf(fontName) !== -1) { + scope.font = fontName; + } + } + if (styles.fontSize != null) { + for (var i = 0; i < scope.fontSizes.length; i++) { + var fontSizeDescriptor = scope.fontSizes[i]; + if (fontSizeDescriptor.size == styles.fontSize) { + scope.fontSize = fontSizeDescriptor; + break; + } + } + } + if (styles.color != null) { + scope.fontColor = styles.color; + updateSelectedColorButton(); + } + }); + } function compileMenu() { wysiwgGui.setCustomElements(scope.textareaCustomMenu); var menuDiv = element.children('div.wysiwyg-menu')[0]; menuDiv.appendChild(wysiwgGui.createMenu(scope.textareaMenu)); $compile(menuDiv)(scope); } - function configureDisabledWatch() { + function configureWatchers() { scope.$watch('disabled', function (newValue) { angular.element('div.wysiwyg-menu').find('button').each(function () { angular.element(this).attr('disabled', newValue); @@ -197,6 +226,7 @@ Requires: angular.element(this).attr('disabled', newValue); }); }); + scope.$watch('fontColor', updateSelectedColorButton); } function configureBootstrapTitle() { if (attrs.enableBootstrapTitle === 'true' && attrs.enableBootstrapTitle !== undefined) { @@ -272,7 +302,7 @@ Requires: scope.hiliteColor = getHiliteColor(); element.find('button.wysiwyg-hiliteColor').css('background-color', scope.hiliteColor); scope.fontColor = scope.cmdValue('forecolor'); - element.find('button.wysiwyg-fontcolor').css('color', scope.fontColor); + updateSelectedColorButton(); scope.isLink = itemIs('A'); }, 0); }); @@ -346,100 +376,101 @@ Requires: scope.setHiliteColor = function () { scope.format('hiliteColor', scope.hiliteColor); }; + scope.textareaCustomFunctions = scope.textareaCustomFunctions || {}; + for (var i in scope.textareaCustomFunctions) { + if (scope[i] == null) { + scope[i] = scope.textareaCustomFunctions[i]; + } else { + console.log('Cannot set custom function `' + i + '`. Already exists function or property'); + } + } scope.format('enableobjectresizing', true); scope.format('styleWithCSS', true); } } - ]).factory('wysiwgGui', [ - 'wysiwgGuiElements', - function (wysiwgGuiElements) { - var ELEMENTS = wysiwgGuiElements; - var custom = {}; - var setCustomElements = function (el) { - custom = el; - }; - var getMenuGroup = function () { - return { - tag: 'div', - classes: 'btn-group btn-group-sm wysiwyg-btn-group-margin' - }; - }; - var getMenuItem = function (item) { - return ELEMENTS[item] || {}; + ]).factory('wysiwgGui', function (wysiwgGuiElements) { + var ELEMENTS = wysiwgGuiElements; + var custom = {}; + var setCustomElements = function (el) { + custom = el; + }; + var getMenuGroup = function () { + return { + tag: 'div', + classes: 'btn-group btn-group-sm wysiwyg-btn-group-margin' }; - var createMenu = function (menu) { - angular.extend(ELEMENTS, custom); - //Get the default menu or the passed in menu - if (angular.isDefined(menu) && menu !== '') { - menu = menu; //stringToArray(menu) - } else { - menu = DEFAULT_MENU; - } - //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()); - for (var j = 0; j < menu[i].length; j++) { - //link has two functions link and unlink - if (menu[i][j] === 'link') { - el = create(getMenuItem('unlink')); - menuGroup.appendChild(el); - } - el = create(getMenuItem(menu[i][j])); + }; + var getMenuItem = function (item) { + return ELEMENTS[item] || {}; + }; + var createMenu = function (menu) { + angular.extend(ELEMENTS, custom); + //Get the default menu or the passed in menu + if (angular.isDefined(menu) && menu !== '') { + menu = menu; //stringToArray(menu) + } else { + menu = DEFAULT_MENU; + } + //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()); + for (var j = 0; j < menu[i].length; j++) { + //link has two functions link and unlink + if (menu[i][j] === 'link') { + el = create(getMenuItem('unlink')); menuGroup.appendChild(el); } - startDiv.appendChild(menuGroup); - } - return startDiv; - }; - function create(obj) { - var el; - if (obj.tag) { - el = document.createElement(obj.tag); - } else if (obj.text) { - el = document.createElement('span'); - } else { - console.log('cannot create this element.'); - el = document.createElement('span'); - return el; - } - if (obj.text && document.all) { - el.innerText = obj.text; - } else { - if(obj.text){ - el.textContent = obj.text; - }else{ - el.textContent = ""; - } - } - if (obj.classes) { - el.className = obj.classes; - } - if (obj.html) { - el.innerHTML = obj.html; + el = create(getMenuItem(menu[i][j])); + menuGroup.appendChild(el); } - if (obj.attributes && obj.attributes.length) { - for (var i in obj.attributes) { - var attr = obj.attributes[i]; - if (attr.name && attr.value) { - el.setAttribute(attr.name, attr.value); - } + startDiv.appendChild(menuGroup); + } + return startDiv; + }; + function create(obj) { + var el; + if (obj.tag) { + el = document.createElement(obj.tag); + } else if (obj.text) { + el = document.createElement('span'); + } else { + console.log('cannot create', obj, 'element.'); + el = document.createElement('span'); + return el; + } + if (obj.text && document.all) { + el.innerText = obj.text; + } else if (obj.text) { + el.textContent = obj.text; + } + if (obj.classes) { + el.className = obj.classes; + } + if (obj.html) { + el.innerHTML = obj.html; + } + if (obj.attributes && obj.attributes.length) { + for (var i in obj.attributes) { + var attr = obj.attributes[i]; + if (attr.name && attr.value) { + el.setAttribute(attr.name, attr.value); } } - if (obj.data && obj.data.length) { - for (var item in obj.data) { - el.appendChild(create(obj.data[item])); - } + } + if (obj.data && obj.data.length) { + for (var item in obj.data) { + el.appendChild(create(obj.data[item])); } - return el; } - return { - createMenu: createMenu, - setCustomElements: setCustomElements - }; + return el; } - ]).value('wysiwgGuiElements', { + return { + createMenu: createMenu, + setCustomElements: setCustomElements + }; + }).value('wysiwgGuiElements', { 'bold': { tag: 'button', classes: 'btn btn-default', @@ -922,7 +953,7 @@ Requires: }, 'hilite-color': { tag: 'button', - classes: 'btn btn-default wysiwyg-colorpicker wysiwyg-fontcolor', + classes: 'btn btn-default wysiwyg-colorpicker wysiwyg-hilitecolor', text: 'H', attributes: [ { @@ -957,7 +988,7 @@ Requires: attributes: [ { name: 'title', - value: 'Font' + value: 'Image' }, { name: 'ng-model', @@ -1070,4 +1101,4 @@ Requires: }] } }); -}(angular)); +}(angular)); \ No newline at end of file diff --git a/dist/angular-wysiwyg.min.js b/dist/angular-wysiwyg.min.js index 1e94c44..92d5b9d 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"==t&&(t=""),u.$setViewValue(t)}),h.on("keydown",function(t){if(9==t.keyCode){{var e=(h.html(),window.getSelection());e.anchorOffset}t.preventDefault()}}),h.on("click keyup focus mouseup",function(){a(function(){o.isBold=o.cmdState("bold"),o.isUnderlined=o.cmdState("underline"),o.isStrikethrough=o.cmdState("strikethrough"),o.isItalic=o.cmdState("italic"),o.isSuperscript=p("SUP"),o.isSubscript=p("SUB"),o.isRightJustified=o.cmdState("justifyright"),o.isLeftJustified=o.cmdState("justifyleft"),o.isCenterJustified=o.cmdState("justifycenter"),o.isPre="pre"===o.cmdValue("formatblock"),o.isBlockquote="blockquote"===o.cmdValue("formatblock"),o.isOrderedList=o.cmdState("insertorderedlist"),o.isUnorderedList=o.cmdState("insertunorderedlist"),o.fonts.forEach(function(t){return o.cmdValue("fontname").indexOf(t)>-1?(o.font=t,!1):void 0}),o.cmdValue("formatblock").toLowerCase(),o.formatBlocks.forEach(function(t){return o.cmdValue("formatblock").toLowerCase()===t.value.toLowerCase()?(o.formatBlock=t,!1):void 0}),o.fontSizes.forEach(function(t){return o.cmdValue("fontsize")===t.value?(o.fontSize=t,!1):void 0}),o.hiliteColor=y(),s.find("button.wysiwyg-hiliteColor").css("background-color",o.hiliteColor),o.fontColor=o.cmdValue("forecolor"),m(),o.isLink=p("A")},0)})}function p(t){var e=window.getSelection().getRangeAt(0);return e&&(e.startContainer.parentNode.tagName===t.toUpperCase()||e.endContainer.parentNode.tagName===t.toUpperCase())?!0:!1}function y(){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",textareaCustomFunctions:"=textareaCustomFunctions"},replace:!0,require:"ngModel",link:o,transclude:!0}}]).factory("wysiwgGui",function(e){function n(t){var e;if(t.tag)e=document.createElement(t.tag);else{if(!t.text)return console.log("cannot create",t,"element."),e=document.createElement("span");e=document.createElement("span")}if(t.text&&document.all?e.innerText=t.text: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={},o=function(t){l=t},s=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 o,u=document.createElement("div"),c=0;c' + '' + '' + - '' + + '' + + ' Insert Image' + + ' ' + + ' File' + + ' URL' + + ' Flickr' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' Image URL' + + ' ' + + ' ' + + ' ' + + ' Add Image' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' Attributes'+ + ' '+ + ' '+ + ' Alt text'+ + ' '+ + ' '+ + ' '+ + ' '+ + ' '+ + ' Width'+ + ' '+ + ' '+ + ' '+ + ' Height'+ + ' '+ + ' '+ + ' '+ + '' + + '' + + '' + '', restrict: 'E', scope: { @@ -67,6 +125,7 @@ Requires: textareaCustomMenu: '=textareaCustomMenu', fn: '&', disabled: '=?disabled', + textareaCustomFunctions: '=textareaCustomFunctions' }, replace: true, require: 'ngModel', @@ -76,7 +135,8 @@ Requires: function link(scope, element, attrs, ngModelController) { - var textarea = element.find('div.wysiwyg-textarea'); + var textarea = element.find('div.wysiwyg-textarea'), + textareaRaw = textarea.next(); scope.isLink = false; @@ -124,15 +184,11 @@ Requires: }, { name: 'Heading 6', value: 'h6' - }, ]; + },]; scope.formatBlock = scope.formatBlocks[0]; scope.fontSize = scope.fontSizes[1]; - if (angular.isArray(scope.cssClasses)) { - scope.cssClasses.unshift('css'); - scope.cssClass = scope.cssClasses[0]; - } scope.fonts = [ 'Georgia', @@ -154,14 +210,109 @@ Requires: scope.font = scope.fonts[6]; + scope.htmlMode = true; + + scope.files = { user: [], course: [] }; + + scope.imageAlt = ''; + scope.imageWidth = ''; + scope.imageHeight = ''; + scope.imageUrl = ''; + + scope.imageView = 'file'; + + scope.changeImageView = function(type) { + scope.imageView = type; + }; + + var flickr; + scope.flickrPhotos = [{},{},{}]; + + scope.flickrUrl = function(photo) { + return ['http://c2.staticflickr.com',photo.farm,photo.server,photo.id+'_'+photo.secret+'_z.jpg'].join('/'); + }; + + scope.selectImage = function(url) { + if(!url) { return false; } + scope.format('insertimage', url); + applyImageParams(url); + element.find('.wysiwyg-image-uploader').addClass('hidden'); + }; + + function applyImageParams(url) { + var img = textarea.find("img[src='"+url+"']"); + if (scope.imageWidth) { img.attr("width", scope.imageWidth); } + if (scope.imageHeight) { img.attr("height", scope.imageHeight); } + if (scope.imageAlt) { img.attr("alt", scope.imageAlt); } + } + + scope.startFlickrSearch = function(x) { + flickr.photos.search({ + text: x + }, function(err, result) { + if(err) { throw new Error(err); } + scope.flickrPhotos = result.photos.photo; + scope.$apply(); + window.console.log(scope.flickrPhotos); + }); + }; + init(); function init() { - + applyDefaultsFromStyle(); compileMenu(); - configureDisabledWatch(); + configureWatchers(); configureBootstrapTitle(); configureListeners(); + getFiles(); + setupFlickr(); + } + + function setupFlickr() { + flickr = new Flickr({ + api_key: "10e1de182b3a6654302eb521c898de0e" + }); + } + + function getFiles() { + $http.get('/api/v1/users/self/files') + .then(function(resp) { + scope.files.user = resp.data; + }) + ; + } + + function updateSelectedColorButton(){ + element.find('button.wysiwyg-fontcolor').css('color', scope.fontColor); + } + + function applyDefaultsFromStyle() { + $timeout(function () { + var textArea = element.find(".wysiwyg-textarea")[0]; + var styles = $window.getComputedStyle(textArea, null); + if (styles.fontFamily != null) { + var fontName = styles.fontFamily.split(",")[0]; + //Remove "'" symbols from style name + fontName = fontName.slice(1, -1); + if (scope.fonts.indexOf(fontName) !== -1) { + scope.font = fontName; + } + } + if (styles.fontSize != null) { + for (var i = 0; i < scope.fontSizes.length; i++) { + var fontSizeDescriptor = scope.fontSizes[i]; + if (fontSizeDescriptor.size == styles.fontSize) { + scope.fontSize = fontSizeDescriptor; + break; + } + } + } + if (styles.color != null) { + scope.fontColor = styles.color; + updateSelectedColorButton(); + } + }); } function compileMenu() { @@ -171,15 +322,17 @@ Requires: $compile(menuDiv)(scope); } - function configureDisabledWatch() { - scope.$watch('disabled', function(newValue) { - angular.element('div.wysiwyg-menu').find('button').each(function() { + function configureWatchers() { + scope.$watch('disabled', function (newValue) { + angular.element('div.wysiwyg-menu').find('button').each(function () { angular.element(this).attr('disabled', newValue); }); - angular.element('div.wysiwyg-menu').find('select').each(function() { + angular.element('div.wysiwyg-menu').find('select').each(function () { angular.element(this).attr('disabled', newValue); }); }); + + scope.$watch('fontColor', updateSelectedColorButton); } function configureBootstrapTitle() { @@ -199,12 +352,12 @@ Requires: function configureListeners() { //Send message to calling controller that a button has been clicked. - angular.element('.wysiwyg-menu').find('button').on('click', function() { + angular.element('.wysiwyg-menu').find('button').on('click', function () { var title = angular.element(this); scope.$emit('wysiwyg.click', title.attr('title') || title.attr('data-original-title')); }); - textarea.on('input keyup paste mouseup', function() { + textarea.on('input keyup paste mouseup', function () { var html = textarea.html(); if (html == '') { @@ -212,15 +365,15 @@ Requires: } ngModelController.$setViewValue(html); - }); + }); - textarea.on('keydown', function(event){ - if (event.keyCode == 9){ + textarea.on('keydown', function (event) { + 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); @@ -228,8 +381,8 @@ Requires: } }); - textarea.on('click keyup focus mouseup', function() { - $timeout(function() { + textarea.on('click keyup focus mouseup', function () { + $timeout(function () { scope.isBold = scope.cmdState('bold'); scope.isUnderlined = scope.cmdState('underline'); scope.isStrikethrough = scope.cmdState('strikethrough'); @@ -245,21 +398,21 @@ Requires: scope.isOrderedList = scope.cmdState('insertorderedlist'); scope.isUnorderedList = scope.cmdState('insertunorderedlist'); - scope.fonts.forEach(function(v, k) { //works but kinda crappy. + scope.fonts.forEach(function (v, k) { //works but kinda crappy. if (scope.cmdValue('fontname').indexOf(v) > -1) { scope.font = v; return false; } }); scope.cmdValue('formatblock').toLowerCase(); - scope.formatBlocks.forEach(function(v, k) { + scope.formatBlocks.forEach(function (v, k) { if (scope.cmdValue('formatblock').toLowerCase() === v.value.toLowerCase()) { scope.formatBlock = v; return false; } }); - scope.fontSizes.forEach(function(v, k) { + scope.fontSizes.forEach(function (v, k) { if (scope.cmdValue('fontsize') === v.value) { scope.fontSize = v; return false; @@ -270,7 +423,7 @@ Requires: element.find('button.wysiwyg-hiliteColor').css('background-color', scope.hiliteColor); scope.fontColor = scope.cmdValue('forecolor'); - element.find('button.wysiwyg-fontcolor').css('color', scope.fontColor); + updateSelectedColorButton(); scope.isLink = itemIs('A'); @@ -314,79 +467,101 @@ Requires: } // model -> view - ngModelController.$render = function() { + ngModelController.$render = function () { textarea.html(ngModelController.$viewValue); }; - scope.format = function(cmd, arg) { + scope.format = function (cmd, arg) { document.execCommand(cmd, false, arg); }; - scope.cmdState = function(cmd) { + scope.cmdState = function (cmd) { return document.queryCommandState(cmd); }; - scope.cmdValue = function(cmd) { + scope.cmdValue = function (cmd) { return document.queryCommandValue(cmd); }; - scope.createLink = function() { + scope.toggleHtml = function() { + scope.htmlMode = !scope.htmlMode; + if(scope.htmlMode){ + var rawValue = $('').html(textareaRaw.html()).text(); + textarea.html(rawValue); + textarea.trigger("click"); + textarea.trigger("input"); + } + }; + + scope.createLink = function () { var input = prompt('Enter the link URL'); if (input && input !== undefined) scope.format('createlink', input); }; - scope.insertImage = function() { - var input = prompt('Enter the image URL'); - if (input && input !== undefined) - scope.format('insertimage', input); + // scope.insertImage = function () { + // var input = prompt('Enter the image URL'); + // if (input && input !== undefined) + // scope.format('insertimage', input); + // }; + + scope.insertImage = function () { + var uploader = element.find('.wysiwyg-image-uploader'); + uploader.toggleClass('hidden'); }; - scope.setFont = function() { + scope.setFont = function () { scope.format('fontname', scope.font); }; - scope.setFontSize = function() { + scope.setFontSize = function () { scope.format('fontsize', scope.fontSize.value); }; - scope.setFormatBlock = function() { + scope.setFormatBlock = function () { scope.format('formatBlock', scope.formatBlock.value); }; - scope.setFontColor = function() { + scope.setFontColor = function () { scope.format('forecolor', scope.fontColor); }; - scope.setHiliteColor = function() { + scope.setHiliteColor = function () { scope.format('hiliteColor', scope.hiliteColor); }; - + scope.textareaCustomFunctions = scope.textareaCustomFunctions || {}; + for (var i in scope.textareaCustomFunctions) { + if (scope[i] == null) { + scope[i] = scope.textareaCustomFunctions[i]; + } else { + console.log('Cannot set custom function `' + i + '`. Already exists function or property'); + } + } scope.format('enableobjectresizing', true); scope.format('styleWithCSS', true); } - }) - .factory('wysiwgGui', function(wysiwgGuiElements) { + }]) + .factory('wysiwgGui', [ 'wysiwgGuiElements', function (wysiwgGuiElements) { var ELEMENTS = wysiwgGuiElements; var custom = {}; - var setCustomElements = function(el) { + var setCustomElements = function (el) { custom = el; }; - var getMenuGroup = function() { + var getMenuGroup = function () { return { tag: 'div', classes: 'btn-group btn-group-sm wysiwyg-btn-group-margin', }; }; - var getMenuItem = function(item) { + var getMenuItem = function (item) { return ELEMENTS[item] || {}; }; - var createMenu = function(menu) { + var createMenu = function (menu) { angular.extend(ELEMENTS, custom); @@ -428,7 +603,7 @@ Requires: } else if (obj.text) { el = document.createElement('span'); } else { - console.log('cannot create this element.'); + console.log('cannot create', obj, 'element.'); el = document.createElement('span'); return el; } @@ -470,7 +645,7 @@ Requires: setCustomElements: setCustomElements }; - }) + }]) .value('wysiwgGuiElements', { 'bold': { tag: 'button', @@ -861,7 +1036,7 @@ Requires: }, 'hilite-color': { tag: 'button', - classes: 'btn btn-default wysiwyg-colorpicker wysiwyg-fontcolor', + classes: 'btn btn-default wysiwyg-colorpicker wysiwyg-hilitecolor', text: 'H', attributes: [{ name: 'title', @@ -975,6 +1150,28 @@ Requires: tag: 'i', classes: 'fa fa-unlink' }] + }, + 'toggle-mode': { + tag: 'button', + classes: 'btn btn-default', + attributes: [ + { + name: 'title', + value: 'Toggle HTML mode' + }, + { + name: 'ng-click', + value: 'toggleHtml()' + }, + { + name: 'type', + value: 'button' + } + ], + data: [{ + tag: 'i', + classes: 'fa fa-edit' + }] } }); })(angular);