diff --git a/public/javascript/simplemappr.admin.js b/public/javascript/simplemappr.admin.js index c5d23129..531fd377 100644 --- a/public/javascript/simplemappr.admin.js +++ b/public/javascript/simplemappr.admin.js @@ -41,6 +41,7 @@ var SimpleMapprAdmin = (function($, window, sm) { api_list: $('#admin-api-list'), init: function() { + this.loadWYSIWYG(); this.loadUserList(); this.bindTools(); this.loadCitationList(); @@ -59,6 +60,16 @@ var SimpleMapprAdmin = (function($, window, sm) { return decodeURIComponent(results[1].replace(/\+/g, " ")); }, + loadWYSIWYG: function() { + $.trumbowyg.svgPath = '/public/stylesheets/raw/icons.svg'; + $('#citation-reference').trumbowyg({ + removeformatPasted: true, + btns: [['bold', 'italic']], + autogrow: true, + semantic: false + }); + }, + loadUserList: function(object) { var self = this, obj = object || {}, @@ -122,19 +133,36 @@ var SimpleMapprAdmin = (function($, window, sm) { }); $('#citation-doi').on('blur', function() { - var val = $(this).val(); + var val = $(this).val(), citation = "", matches; if(val.length > 0 && $('#citation-reference').val().length === 0) { sm.showSpinner(); - $.getJSON("http://search.crossref.org/dois?q=" + encodeURIComponent(val), function(data) { - if (data && data.length > 0) { - $.each(data[0], function(key, value) { - if(key === "fullCitation") { - $('#citation-reference').val(value); - } - if(key === "year") { - $('#citation-year').val(value); - } - }); + $.ajax({ + type: 'POST', + url: "https://doi.org/" + encodeURIComponent(val), + dataType: 'json', + beforeSend: function(xhr) { + xhr.setRequestHeader('Accept', 'application/vnd.citationstyles.csl+json;q=1.0'); + }, + success: function(data) { + $('#citation-surname').val(data.author[0].family); + $('#citation-year').val(data.issued["date-parts"][0][0]); + }, + error: function() { + } + }); + $.ajax({ + type: 'POST', + url: "https://doi.org/" + encodeURIComponent(val), + dataType: 'text', + beforeSend: function(xhr) { + xhr.setRequestHeader('Accept', 'text/x-bibliography; style=american-journal-of-botany'); + }, + success: function(data) { + matches = data.match(/^(.*)(?:available at:)/i); + $("#citation-reference").val(matches[1].trim()); + $(".trumbowyg-editor").text(matches[1].trim()); + }, + error: function() { } }); sm.hideSpinner(); @@ -233,6 +261,7 @@ var SimpleMapprAdmin = (function($, window, sm) { success : function(data) { if(data.status === "ok") { $('#map-admin').find(".citation").val(""); + $('#citation-reference').trumbowyg('empty'); $.each(["reference", "surname", "year"], function() { $('#citation-'+this).removeClass('ui-state-error'); }); diff --git a/public/javascript/simplemappr.js b/public/javascript/simplemappr.js index e3749ccf..bf49a63c 100644 --- a/public/javascript/simplemappr.js +++ b/public/javascript/simplemappr.js @@ -2603,7 +2603,7 @@ var SimpleMappr = (function($, window, document) { }, bindTextAreaResizers: function() { - $.each([this.vars.fieldSetsPoints, this.vars.fieldSetsRegions, this.vars.fieldSetsWKT, '#map-admin'], function() { + $.each([this.vars.fieldSetsPoints, this.vars.fieldSetsRegions, this.vars.fieldSetsWKT], function() { $(this).find('textarea.resizable:not(.textarea-processed)').TextAreaResizer(); }); }, diff --git a/public/javascript/trumbowyg.js b/public/javascript/trumbowyg.js new file mode 100755 index 00000000..b9d8767b --- /dev/null +++ b/public/javascript/trumbowyg.js @@ -0,0 +1,1578 @@ +/** + * Trumbowyg v2.4.2 - A lightweight WYSIWYG editor + * Trumbowyg core file + * ------------------------ + * @link http://alex-d.github.io/Trumbowyg + * @license MIT + * @author Alexandre Demode (Alex-D) + * Twitter : @AlexandreDemode + * Website : alex-d.fr + */ + +jQuery.trumbowyg = { + langs: { + en: { + viewHTML: 'View HTML', + + undo: 'Undo', + redo: 'Redo', + + formatting: 'Formatting', + p: 'Paragraph', + blockquote: 'Quote', + code: 'Code', + header: 'Header', + + bold: 'Bold', + italic: 'Italic', + strikethrough: 'Stroke', + underline: 'Underline', + + strong: 'Strong', + em: 'Emphasis', + del: 'Deleted', + + superscript: 'Superscript', + subscript: 'Subscript', + + unorderedList: 'Unordered list', + orderedList: 'Ordered list', + + insertImage: 'Insert Image', + link: 'Link', + createLink: 'Insert link', + unlink: 'Remove link', + + justifyLeft: 'Align Left', + justifyCenter: 'Align Center', + justifyRight: 'Align Right', + justifyFull: 'Align Justify', + + horizontalRule: 'Insert horizontal rule', + removeformat: 'Remove format', + + fullscreen: 'Fullscreen', + + close: 'Close', + + submit: 'Confirm', + reset: 'Cancel', + + required: 'Required', + description: 'Description', + title: 'Title', + text: 'Text', + target: 'Target' + } + }, + + // Plugins + plugins: {}, + + // SVG Path globally + svgPath: null +}; + + +(function (navigator, window, document, $) { + 'use strict'; + + $.fn.trumbowyg = function (options, params) { + var trumbowygDataName = 'trumbowyg'; + if (options === Object(options) || !options) { + return this.each(function () { + if (!$(this).data(trumbowygDataName)) { + $(this).data(trumbowygDataName, new Trumbowyg(this, options)); + } + }); + } + if (this.length === 1) { + try { + var t = $(this).data(trumbowygDataName); + switch (options) { + // Exec command + case 'execCmd': + return t.execCmd(params.cmd, params.param, params.forceCss); + + // Modal box + case 'openModal': + return t.openModal(params.title, params.content); + case 'closeModal': + return t.closeModal(); + case 'openModalInsert': + return t.openModalInsert(params.title, params.fields, params.callback); + + // Range + case 'saveRange': + return t.saveRange(); + case 'getRange': + return t.range; + case 'getRangeText': + return t.getRangeText(); + case 'restoreRange': + return t.restoreRange(); + + // Enable/disable + case 'enable': + return t.toggleDisable(false); + case 'disable': + return t.toggleDisable(true); + + // Destroy + case 'destroy': + return t.destroy(); + + // Empty + case 'empty': + return t.empty(); + + // HTML + case 'html': + return t.html(params); + } + } catch (c) { + } + } + + return false; + }; + + // @param: editorElem is the DOM element + var Trumbowyg = function (editorElem, options) { + var t = this, + trumbowygIconsId = 'trumbowyg-icons'; + + // Get the document of the element. It use to makes the plugin + // compatible on iframes. + t.doc = editorElem.ownerDocument || document; + + // jQuery object of the editor + t.$ta = $(editorElem); // $ta : Textarea + t.$c = $(editorElem); // $c : creator + + options = options || {}; + + // Localization management + if (options.lang != null || $.trumbowyg.langs[options.lang] != null) { + t.lang = $.extend(true, {}, $.trumbowyg.langs.en, $.trumbowyg.langs[options.lang]); + } else { + t.lang = $.trumbowyg.langs.en; + } + + // SVG path + var svgPathOption = $.trumbowyg.svgPath != null ? $.trumbowyg.svgPath : options.svgPath; + t.hasSvg = svgPathOption !== false; + t.svgPath = !!t.doc.querySelector('base') ? window.location.href.split('#')[0] : ''; + if ($('#' + trumbowygIconsId, t.doc).length === 0 && svgPathOption !== false) { + if (svgPathOption == null) { + try { + throw new Error(); + } catch (e) { + var stackLines = e.stack.split('\n'); + + for (var i in stackLines) { + if (!stackLines[i].match(/http[s]?:\/\//)) { + continue; + } + svgPathOption = stackLines[Number(i)].match(/((http[s]?:\/\/.+\/)([^\/]+\.js))(\?.*)?:/)[1].split('/'); + svgPathOption.pop(); + svgPathOption = svgPathOption.join('/') + '/ui/icons.svg'; + break; + } + } + } + + var div = t.doc.createElement('div'); + div.id = trumbowygIconsId; + t.doc.body.insertBefore(div, t.doc.body.childNodes[0]); + $.ajax({ + async: true, + type: 'GET', + contentType: 'application/x-www-form-urlencoded; charset=UTF-8', + dataType: 'xml', + url: svgPathOption, + data: null, + beforeSend: null, + complete: null, + success: function (data) { + div.innerHTML = new XMLSerializer().serializeToString(data.documentElement); + } + }); + } + + + /** + * When the button is associated to a empty object + * fn and title attributs are defined from the button key value + * + * For example + * foo: {} + * is equivalent to : + * foo: { + * fn: 'foo', + * title: this.lang.foo + * } + */ + var h = t.lang.header, // Header translation + isBlinkFunction = function () { + return (window.chrome || (window.Intl && Intl.v8BreakIterator)) && 'CSS' in window; + }; + t.btnsDef = { + viewHTML: { + fn: 'toggle' + }, + + undo: { + isSupported: isBlinkFunction, + key: 'Z' + }, + redo: { + isSupported: isBlinkFunction, + key: 'Y' + }, + + p: { + fn: 'formatBlock' + }, + blockquote: { + fn: 'formatBlock' + }, + h1: { + fn: 'formatBlock', + title: h + ' 1' + }, + h2: { + fn: 'formatBlock', + title: h + ' 2' + }, + h3: { + fn: 'formatBlock', + title: h + ' 3' + }, + h4: { + fn: 'formatBlock', + title: h + ' 4' + }, + subscript: { + tag: 'sub' + }, + superscript: { + tag: 'sup' + }, + + bold: { + key: 'B', + tag: 'b' + }, + italic: { + key: 'I', + tag: 'i' + }, + underline: { + tag: 'u' + }, + strikethrough: { + tag: 'strike' + }, + + strong: { + fn: 'bold', + key: 'B' + }, + em: { + fn: 'italic', + key: 'I' + }, + del: { + fn: 'strikethrough' + }, + + createLink: { + key: 'K', + tag: 'a' + }, + unlink: {}, + + insertImage: {}, + + justifyLeft: { + tag: 'left', + forceCss: true + }, + justifyCenter: { + tag: 'center', + forceCss: true + }, + justifyRight: { + tag: 'right', + forceCss: true + }, + justifyFull: { + tag: 'justify', + forceCss: true + }, + + unorderedList: { + fn: 'insertUnorderedList', + tag: 'ul' + }, + orderedList: { + fn: 'insertOrderedList', + tag: 'ol' + }, + + horizontalRule: { + fn: 'insertHorizontalRule' + }, + + removeformat: {}, + + fullscreen: { + class: 'trumbowyg-not-disable' + }, + close: { + fn: 'destroy', + class: 'trumbowyg-not-disable' + }, + + // Dropdowns + formatting: { + dropdown: ['p', 'blockquote', 'h1', 'h2', 'h3', 'h4'], + ico: 'p' + }, + link: { + dropdown: ['createLink', 'unlink'] + } + }; + + // Defaults Options + t.o = $.extend(true, {}, { + lang: 'en', + useComposition: true, + + fixedBtnPane: false, + fixedFullWidth: false, + autogrow: false, + + prefix: 'trumbowyg-', + + semantic: true, + resetCss: false, + removeformatPasted: false, + tagsToRemove: [], + + btnsGrps: { + design: ['bold', 'italic', 'underline', 'strikethrough'], + semantic: ['strong', 'em', 'del'], + justify: ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'], + lists: ['unorderedList', 'orderedList'] + }, + btns: [ + ['viewHTML'], + ['undo', 'redo'], + ['formatting'], + 'btnGrp-semantic', + ['superscript', 'subscript'], + ['link'], + ['insertImage'], + 'btnGrp-justify', + 'btnGrp-lists', + ['horizontalRule'], + ['removeformat'], + ['fullscreen'] + ], + // For custom button definitions + btnsDef: {}, + + inlineElementsSelector: 'a,abbr,acronym,b,caption,cite,code,col,dfn,dir,dt,dd,em,font,hr,i,kbd,li,q,span,strikeout,strong,sub,sup,u', + + pasteHandlers: [], + + imgDblClickHandler: function () { + var $img = $(this), + src = $img.attr('src'), + base64 = '(Base64)'; + + if (src.indexOf('data:image') === 0) { + src = base64; + } + + t.openModalInsert(t.lang.insertImage, { + url: { + label: 'URL', + value: src, + required: true + }, + alt: { + label: t.lang.description, + value: $img.attr('alt') + } + }, function (v) { + if (v.src !== base64) { + $img.attr({ + src: v.src + }); + } + $img.attr({ + alt: v.alt + }); + return true; + }); + return false; + }, + + plugins: {} + }, options); + + t.disabled = t.o.disabled || (editorElem.nodeName === 'TEXTAREA' && editorElem.disabled); + + if (options.btns) { + t.o.btns = options.btns; + } else if (!t.o.semantic) { + t.o.btns[4] = 'btnGrp-design'; + } + + $.each(t.o.btnsDef, function (btnName, btnDef) { + t.addBtnDef(btnName, btnDef); + }); + + // put this here in the event it would be merged in with options + t.eventNamespace = 'trumbowyg-event'; + + // Keyboard shortcuts are load in this array + t.keys = []; + + // Tag to button dynamically hydrated + t.tagToButton = {}; + t.tagHandlers = []; + + // Admit multiple paste handlers + t.pasteHandlers = [].concat(t.o.pasteHandlers); + + t.init(); + }; + + Trumbowyg.prototype = { + init: function () { + var t = this; + t.height = t.$ta.height(); + + t.initPlugins(); + + try { + // Disable image resize, try-catch for old IE + t.doc.execCommand('enableObjectResizing', false, false); + t.doc.execCommand('defaultParagraphSeparator', false, 'p'); + } catch (e) { + } + + t.buildEditor(); + t.buildBtnPane(); + + t.fixedBtnPaneEvents(); + + t.buildOverlay(); + + setTimeout(function () { + if (t.disabled) { + t.toggleDisable(true); + } + t.$c.trigger('tbwinit'); + }); + }, + + addBtnDef: function (btnName, btnDef) { + this.btnsDef[btnName] = btnDef; + }, + + buildEditor: function () { + var t = this, + prefix = t.o.prefix, + html = ''; + + t.$box = $('
', { + class: prefix + 'box ' + prefix + 'editor-visible ' + prefix + t.o.lang + ' trumbowyg' + }); + + // $ta = Textarea + // $ed = Editor + t.isTextarea = t.$ta.is('textarea'); + if (t.isTextarea) { + html = t.$ta.val(); + t.$ed = $(''); + t.$box + .insertAfter(t.$ta) + .append(t.$ed, t.$ta); + } else { + t.$ed = t.$ta; + html = t.$ed.html(); + + t.$ta = $('', { + name: t.$ta.attr('id'), + height: t.height + }).val(html); + + t.$box + .insertAfter(t.$ed) + .append(t.$ta, t.$ed); + t.syncCode(); + } + + t.$ta + .addClass(prefix + 'textarea') + .attr('tabindex', -1) + ; + + t.$ed + .addClass(prefix + 'editor') + .attr({ + contenteditable: true, + dir: t.lang._dir || 'ltr' + }) + .html(html) + ; + + if (t.o.tabindex) { + t.$ed.attr('tabindex', t.o.tabindex); + } + + if (t.$c.is('[placeholder]')) { + t.$ed.attr('placeholder', t.$c.attr('placeholder')); + } + + if (t.o.resetCss) { + t.$ed.addClass(prefix + 'reset-css'); + } + + if (!t.o.autogrow) { + t.$ta.add(t.$ed).css({ + height: t.height + }); + } + + t.semanticCode(); + + + var ctrl = false, + composition = false, + debounceButtonPaneStatus; + + t.$ed + .on('dblclick', 'img', t.o.imgDblClickHandler) + .on('keydown', function (e) { + composition = t.o.useComposition && (e.which === 229); + + if (e.ctrlKey) { + ctrl = true; + var k = t.keys[String.fromCharCode(e.which).toUpperCase()]; + + try { + t.execCmd(k.fn, k.param); + return false; + } catch (c) { + } + } + }) + .on('keyup input', function (e) { + if (e.which >= 37 && e.which <= 40) { + return; + } + + if (e.ctrlKey && (e.which === 89 || e.which === 90)) { + t.$c.trigger('tbwchange'); + } else if (!ctrl && e.which !== 17 && !composition) { + t.semanticCode(false, e.which === 13); + t.$c.trigger('tbwchange'); + } + + setTimeout(function () { + ctrl = false; + }, 200); + }) + .on('mouseup keydown keyup', function () { + clearTimeout(debounceButtonPaneStatus); + debounceButtonPaneStatus = setTimeout(function () { + t.updateButtonPaneStatus(); + }, 50); + }) + .on('focus blur', function (e) { + t.$c.trigger('tbw' + e.type); + if (e.type === 'blur') { + $('.' + prefix + 'active-button', t.$btnPane).removeClass(prefix + 'active-button ' + prefix + 'active'); + } + }) + .on('cut', function () { + setTimeout(function () { + t.semanticCode(false, true); + t.$c.trigger('tbwchange'); + }, 0); + }) + .on('paste', function (e) { + if (t.o.removeformatPasted) { + e.preventDefault(); + + try { + // IE + var text = window.clipboardData.getData('Text'); + + try { + // <= IE10 + t.doc.selection.createRange().pasteHTML(text); + } catch (c) { + // IE 11 + t.doc.getSelection().getRangeAt(0).insertNode(t.doc.createTextNode(text)); + } + } catch (d) { + // Not IE + t.execCmd('insertText', (e.originalEvent || e).clipboardData.getData('text/plain')); + } + } + + // Call pasteHandlers + $.each(t.pasteHandlers, function (i, pasteHandler) { + pasteHandler(e); + }); + + setTimeout(function () { + t.semanticCode(false, true); + t.$c.trigger('tbwpaste', e); + }, 0); + }); + t.$ta.on('keyup paste', function () { + t.$c.trigger('tbwchange'); + }); + + t.$box.on('keydown', function (e) { + if (e.which === 27 && $('.' + prefix + 'modal-box', t.$box).length === 1) { + t.closeModal(); + return false; + } + }); + }, + + + // Build button pane, use o.btns option + buildBtnPane: function () { + var t = this, + prefix = t.o.prefix; + + var $btnPane = t.$btnPane = $('', { + class: prefix + 'button-pane' + }); + + $.each(t.o.btns, function (i, btnGrps) { + // Managment of group of buttons + try { + var b = btnGrps.split('btnGrp-'); + if (b[1] != null) { + btnGrps = t.o.btnsGrps[b[1]]; + } + } catch (c) { + } + + if (!$.isArray(btnGrps)) { + btnGrps = [btnGrps]; + } + + var $btnGroup = $('', { + class: prefix + 'button-group ' + ((btnGrps.indexOf('fullscreen') >= 0) ? prefix + 'right' : '') + }); + $.each(btnGrps, function (i, btn) { + try { // Prevent buildBtn error + var $item; + + if (t.isSupportedBtn(btn)) { // It's a supported button + $item = t.buildBtn(btn); + } + + $btnGroup.append($item); + } catch (c) { + } + }); + $btnPane.append($btnGroup); + }); + + t.$box.prepend($btnPane); + }, + + + // Build a button and his action + buildBtn: function (btnName) { // btnName is name of the button + var t = this, + prefix = t.o.prefix, + btn = t.btnsDef[btnName], + isDropdown = btn.dropdown, + hasIcon = btn.hasIcon != null ? btn.hasIcon : true, + textDef = t.lang[btnName] || btnName, + + $btn = $('', { + type: 'button', + class: prefix + btnName + '-button ' + (btn.class || '') + (!hasIcon ? ' ' + prefix + 'textual-button' : ''), + html: t.hasSvg && hasIcon ? '' : (btn.text || btn.title || t.lang[btnName] || btnName), + title: (btn.title || btn.text || textDef) + ((btn.key) ? ' (Ctrl + ' + btn.key + ')' : ''), + tabindex: -1, + mousedown: function () { + if (!isDropdown || $('.' + btnName + '-' + prefix + 'dropdown', t.$box).is(':hidden')) { + $('body', t.doc).trigger('mousedown'); + } + + if (t.$btnPane.hasClass(prefix + 'disable') && !$(this).hasClass(prefix + 'active') && !$(this).hasClass(prefix + 'not-disable')) { + return false; + } + + t.execCmd((isDropdown ? 'dropdown' : false) || btn.fn || btnName, btn.param || btnName, btn.forceCss || false); + + return false; + } + }); + + if (isDropdown) { + $btn.addClass(prefix + 'open-dropdown'); + var dropdownPrefix = prefix + 'dropdown', + $dropdown = $('', { // the dropdown + class: dropdownPrefix + '-' + btnName + ' ' + dropdownPrefix + ' ' + prefix + 'fixed-top', + 'data-dropdown': btnName + }); + $.each(isDropdown, function (i, def) { + if (t.btnsDef[def] && t.isSupportedBtn(def)) { + $dropdown.append(t.buildSubBtn(def)); + } + }); + t.$box.append($dropdown.hide()); + } else if (btn.key) { + t.keys[btn.key] = { + fn: btn.fn || btnName, + param: btn.param || btnName + }; + } + + if (!isDropdown) { + t.tagToButton[(btn.tag || btnName).toLowerCase()] = btnName; + } + + return $btn; + }, + // Build a button for dropdown menu + // @param n : name of the subbutton + buildSubBtn: function (btnName) { + var t = this, + prefix = t.o.prefix, + btn = t.btnsDef[btnName], + hasIcon = btn.hasIcon != null ? btn.hasIcon : true; + + if (btn.key) { + t.keys[btn.key] = { + fn: btn.fn || btnName, + param: btn.param || btnName + }; + } + + t.tagToButton[(btn.tag || btnName).toLowerCase()] = btnName; + + return $('', { + type: 'button', + class: prefix + btnName + '-dropdown-button' + (btn.ico ? ' ' + prefix + btn.ico + '-button' : ''), + html: t.hasSvg && hasIcon ? '' + (btn.text || btn.title || t.lang[btnName] || btnName) : (btn.text || btn.title || t.lang[btnName] || btnName), + title: ((btn.key) ? ' (Ctrl + ' + btn.key + ')' : null), + style: btn.style || null, + mousedown: function () { + $('body', t.doc).trigger('mousedown'); + + t.execCmd(btn.fn || btnName, btn.param || btnName, btn.forceCss || false); + + return false; + } + }); + }, + // Check if button is supported + isSupportedBtn: function (b) { + try { + return this.btnsDef[b].isSupported(); + } catch (c) { + } + return true; + }, + + // Build overlay for modal box + buildOverlay: function () { + var t = this; + t.$overlay = $('', { + class: t.o.prefix + 'overlay' + }).css({ + top: t.$btnPane.outerHeight(), + height: (t.$ed.outerHeight() + 1) + 'px' + }).appendTo(t.$box); + return t.$overlay; + }, + showOverlay: function () { + var t = this; + $(window).trigger('scroll'); + t.$overlay.fadeIn(200); + t.$box.addClass(t.o.prefix + 'box-blur'); + }, + hideOverlay: function () { + var t = this; + t.$overlay.fadeOut(50); + t.$box.removeClass(t.o.prefix + 'box-blur'); + }, + + // Management of fixed button pane + fixedBtnPaneEvents: function () { + var t = this, + fixedFullWidth = t.o.fixedFullWidth, + $box = t.$box; + + if (!t.o.fixedBtnPane) { + return; + } + + t.isFixed = false; + + $(window) + .on('scroll.'+t.eventNamespace+' resize.'+t.eventNamespace, function () { + if (!$box) { + return; + } + + t.syncCode(); + + var scrollTop = $(window).scrollTop(), + offset = $box.offset().top + 1, + bp = t.$btnPane, + oh = bp.outerHeight() - 2; + + if ((scrollTop - offset > 0) && ((scrollTop - offset - t.height) < 0)) { + if (!t.isFixed) { + t.isFixed = true; + bp.css({ + position: 'fixed', + top: 0, + left: fixedFullWidth ? '0' : 'auto', + zIndex: 7 + }); + $([t.$ta, t.$ed]).css({marginTop: bp.height()}); + } + bp.css({ + width: fixedFullWidth ? '100%' : (($box.width() - 1) + 'px') + }); + + $('.' + t.o.prefix + 'fixed-top', $box).css({ + position: fixedFullWidth ? 'fixed' : 'absolute', + top: fixedFullWidth ? oh : oh + (scrollTop - offset) + 'px', + zIndex: 15 + }); + } else if (t.isFixed) { + t.isFixed = false; + bp.removeAttr('style'); + $([t.$ta, t.$ed]).css({marginTop: 0}); + $('.' + t.o.prefix + 'fixed-top', $box).css({ + position: 'absolute', + top: oh + }); + } + }); + }, + + // Disable editor + toggleDisable: function (disable) { + var t = this, + prefix = t.o.prefix; + + t.disabled = disable; + + if (disable) { + t.$ta.attr('disabled', true); + } else { + t.$ta.removeAttr('disabled'); + } + t.$box.toggleClass(prefix + 'disabled', disable); + t.$ed.attr('contenteditable', !disable); + }, + + // Destroy the editor + destroy: function () { + var t = this, + prefix = t.o.prefix, + height = t.height; + + if (t.isTextarea) { + t.$box.after( + t.$ta + .css({height: height}) + .val(t.html()) + .removeClass(prefix + 'textarea') + .show() + ); + } else { + t.$box.after( + t.$ed + .css({height: height}) + .removeClass(prefix + 'editor') + .removeAttr('contenteditable') + .html(t.html()) + .show() + ); + } + + t.$ed.off('dblclick', 'img'); + + t.destroyPlugins(); + + t.$box.remove(); + t.$c.removeData('trumbowyg'); + $('body').removeClass(prefix + 'body-fullscreen'); + t.$c.trigger('tbwclose'); + $(window).off('scroll.'+t.eventNamespace+' resize.'+t.eventNamespace); + }, + + + // Empty the editor + empty: function () { + this.$ta.val(''); + this.syncCode(true); + }, + + + // Function call when click on viewHTML button + toggle: function () { + var t = this, + prefix = t.o.prefix; + t.semanticCode(false, true); + setTimeout(function () { + t.doc.activeElement.blur(); + t.$box.toggleClass(prefix + 'editor-hidden ' + prefix + 'editor-visible'); + t.$btnPane.toggleClass(prefix + 'disable'); + $('.' + prefix + 'viewHTML-button', t.$btnPane).toggleClass(prefix + 'active'); + if (t.$box.hasClass(prefix + 'editor-visible')) { + t.$ta.attr('tabindex', -1); + } else { + t.$ta.removeAttr('tabindex'); + } + }, 0); + }, + + // Open dropdown when click on a button which open that + dropdown: function (name) { + var t = this, + d = t.doc, + prefix = t.o.prefix, + $dropdown = $('[data-dropdown=' + name + ']', t.$box), + $btn = $('.' + prefix + name + '-button', t.$btnPane), + show = $dropdown.is(':hidden'); + + $('body', d).trigger('mousedown'); + + if (show) { + var o = $btn.offset().left; + $btn.addClass(prefix + 'active'); + + $dropdown.css({ + position: 'absolute', + top: $btn.offset().top - t.$btnPane.offset().top + $btn.outerHeight(), + left: (t.o.fixedFullWidth && t.isFixed) ? o + 'px' : (o - t.$btnPane.offset().left) + 'px' + }).show(); + + $(window).trigger('scroll'); + + $('body', d).on('mousedown.'+t.eventNamespace, function () { + $('.' + prefix + 'dropdown', d).hide(); + $('.' + prefix + 'active', d).removeClass(prefix + 'active'); + $('body', d).off('mousedown.'+t.eventNamespace); + }); + } + }, + + + // HTML Code management + html: function (html) { + var t = this; + if (html != null) { + t.$ta.val(html); + t.syncCode(true); + return t; + } + return t.$ta.val(); + }, + syncTextarea: function () { + var t = this; + t.$ta.val(t.$ed.text().trim().length > 0 || t.$ed.find('hr,img,embed,iframe,input').length > 0 ? t.$ed.html() : ''); + }, + syncCode: function (force) { + var t = this; + if (!force && t.$ed.is(':visible')) { + t.syncTextarea(); + } else { + t.$ed.html(t.$ta.val()); + } + + if (t.o.autogrow) { + t.height = t.$ed.height(); + if (t.height !== t.$ta.css('height')) { + t.$ta.css({height: t.height}); + t.$c.trigger('tbwresize'); + } + } + }, + + // Analyse and update to semantic code + // @param force : force to sync code from textarea + // @param full : wrap text nodes in+ semanticCode: function (force, full) { + var t = this; + t.saveRange(); + t.syncCode(force); + + $(t.o.tagsToRemove.join(','), t.$ed).remove(); + + if (t.o.semantic) { + t.semanticTag('b', 'strong'); + t.semanticTag('i', 'em'); + + if (full) { + var inlineElementsSelector = t.o.inlineElementsSelector, + blockElementsSelector = ':not(' + inlineElementsSelector + ')'; + + // Wrap text nodes in span for easier processing + t.$ed.contents().filter(function () { + return this.nodeType === 3 && this.nodeValue.trim().length > 0; + }).wrap(''); + + // Wrap groups of inline elements in paragraphs (recursive) + var wrapInlinesInParagraphsFrom = function ($from) { + if ($from.length !== 0) { + var $finalParagraph = $from.nextUntil(blockElementsSelector).addBack().wrapAll('
').parent(), + $nextElement = $finalParagraph.nextAll(inlineElementsSelector).first(); + $finalParagraph.next('br').remove(); + wrapInlinesInParagraphsFrom($nextElement); + } + }; + wrapInlinesInParagraphsFrom(t.$ed.children(inlineElementsSelector).first()); + + t.semanticTag('div', 'p', true); + + // Unwrap paragraphs content, containing nothing usefull + t.$ed.find('p').filter(function () { + // Don't remove currently being edited element + if (t.range && this === t.range.startContainer) { + return false; + } + return $(this).text().trim().length === 0 && $(this).children().not('br,span').length === 0; + }).contents().unwrap(); + + // Get rid of temporial span's + $('[data-tbw]', t.$ed).contents().unwrap(); + + // Remove empty+ t.$ed.find('p:empty').remove(); + } + + t.restoreRange(); + + t.syncTextarea(); + } + }, + + semanticTag: function (oldTag, newTag, copyAttributes) { + $(oldTag, this.$ed).each(function () { + var $oldTag = $(this); + $oldTag.wrap('<' + newTag + '/>'); + if (copyAttributes) { + $.each($oldTag.prop('attributes'), function () { + $oldTag.parent().attr(this.name, this.value); + }); + } + $oldTag.contents().unwrap(); + }); + }, + + // Function call when user click on "Insert Link" + createLink: function () { + var t = this, + documentSelection = t.doc.getSelection(), + node = documentSelection.focusNode, + url, + title, + target; + + while (['A', 'DIV'].indexOf(node.nodeName) < 0) { + node = node.parentNode; + } + + if (node && node.nodeName === 'A') { + var $a = $(node); + url = $a.attr('href'); + title = $a.attr('title'); + target = $a.attr('target'); + var range = t.doc.createRange(); + range.selectNode(node); + documentSelection.addRange(range); + } + + t.saveRange(); + + t.openModalInsert(t.lang.createLink, { + url: { + label: 'URL', + required: true, + value: url + }, + title: { + label: t.lang.title, + value: title + }, + text: { + label: t.lang.text, + value: t.getRangeText() + }, + target: { + label: t.lang.target, + value: target + } + }, function (v) { // v is value + var link = $(['', v.text, ''].join('')); + if (v.title.length > 0) { + link.attr('title', v.title); + } + if (v.target.length > 0) { + link.attr('target', v.target); + } + t.range.deleteContents(); + t.range.insertNode(link[0]); + return true; + }); + }, + unlink: function () { + var t = this, + documentSelection = t.doc.getSelection(), + node = documentSelection.focusNode; + + if (documentSelection.isCollapsed) { + while (['A', 'DIV'].indexOf(node.nodeName) < 0) { + node = node.parentNode; + } + + if (node && node.nodeName === 'A') { + var range = t.doc.createRange(); + range.selectNode(node); + documentSelection.addRange(range); + } + } + t.execCmd('unlink', undefined, undefined, true); + }, + insertImage: function () { + var t = this; + t.saveRange(); + t.openModalInsert(t.lang.insertImage, { + url: { + label: 'URL', + required: true + }, + alt: { + label: t.lang.description, + value: t.getRangeText() + } + }, function (v) { // v are values + t.execCmd('insertImage', v.url); + $('img[src="' + v.url + '"]:not([alt])', t.$box).attr('alt', v.alt); + return true; + }); + }, + fullscreen: function () { + var t = this, + prefix = t.o.prefix, + fullscreenCssClass = prefix + 'fullscreen', + isFullscreen; + + t.$box.toggleClass(fullscreenCssClass); + isFullscreen = t.$box.hasClass(fullscreenCssClass); + $('body').toggleClass(prefix + 'body-fullscreen', isFullscreen); + $(window).trigger('scroll'); + t.$c.trigger('tbw' + (isFullscreen ? 'open' : 'close') + 'fullscreen'); + }, + + + /* + * Call method of trumbowyg if exist + * else try to call anonymous function + * and finaly native execCommand + */ + execCmd: function (cmd, param, forceCss, skipTrumbowyg) { + var t = this; + skipTrumbowyg = !!skipTrumbowyg || ''; + + if (cmd !== 'dropdown') { + t.$ed.focus(); + } + + try { + t.doc.execCommand('styleWithCSS', false, forceCss || false); + } catch (c) { + } + + try { + t[cmd + skipTrumbowyg](param); + } catch (c) { + try { + cmd(param); + } catch (e2) { + if (cmd === 'insertHorizontalRule') { + param = undefined; + } else if (cmd === 'formatBlock' && (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') !== -1)) { + param = '<' + param + '>'; + } + + t.doc.execCommand(cmd, false, param); + + t.syncCode(); + t.semanticCode(false, true); + } + + if (cmd !== 'dropdown') { + t.updateButtonPaneStatus(); + t.$c.trigger('tbwchange'); + } + } + }, + + + // Open a modal box + openModal: function (title, content) { + var t = this, + prefix = t.o.prefix; + + // No open a modal box when exist other modal box + if ($('.' + prefix + 'modal-box', t.$box).length > 0) { + return false; + } + + t.saveRange(); + t.showOverlay(); + + // Disable all btnPane btns + t.$btnPane.addClass(prefix + 'disable'); + + // Build out of ModalBox, it's the mask for animations + var $modal = $('
', { + class: prefix + 'modal ' + prefix + 'fixed-top' + }).css({ + top: t.$btnPane.height() + }).appendTo(t.$box); + + // Click on overlay close modal by cancelling them + t.$overlay.one('click', function () { + $modal.trigger('tbwcancel'); + return false; + }); + + // Build the form + var $form = $('', { + action: '', + html: content + }) + .on('submit', function () { + $modal.trigger('tbwconfirm'); + return false; + }) + .on('reset', function () { + $modal.trigger('tbwcancel'); + return false; + }); + + + // Build ModalBox and animate to show them + var $box = $('', { + class: prefix + 'modal-box', + html: $form + }) + .css({ + top: '-' + t.$btnPane.outerHeight() + 'px', + opacity: 0 + }) + .appendTo($modal) + .animate({ + top: 0, + opacity: 1 + }, 100); + + + // Append title + $('', { + text: title, + class: prefix + 'modal-title' + }).prependTo($box); + + $modal.height($box.outerHeight() + 10); + + + // Focus in modal box + $('input:first', $box).focus(); + + + // Append Confirm and Cancel buttons + t.buildModalBtn('submit', $box); + t.buildModalBtn('reset', $box); + + + $(window).trigger('scroll'); + + return $modal; + }, + // @param n is name of modal + buildModalBtn: function (n, $modal) { + var t = this, + prefix = t.o.prefix; + + return $('', { + class: prefix + 'modal-button ' + prefix + 'modal-' + n, + type: n, + text: t.lang[n] || n + }).appendTo($('form', $modal)); + }, + // close current modal box + closeModal: function () { + var t = this, + prefix = t.o.prefix; + + t.$btnPane.removeClass(prefix + 'disable'); + t.$overlay.off(); + + // Find the modal box + var $modalBox = $('.' + prefix + 'modal-box', t.$box); + + $modalBox.animate({ + top: '-' + $modalBox.height() + }, 100, function () { + $modalBox.parent().remove(); + t.hideOverlay(); + }); + + t.restoreRange(); + }, + // Preformated build and management modal + openModalInsert: function (title, fields, cmd) { + var t = this, + prefix = t.o.prefix, + lg = t.lang, + html = '', + CONFIRM_EVENT = 'tbwconfirm'; + + $.each(fields, function (fieldName, field) { + var l = field.label, + n = field.name || fieldName, + a = field.attributes || {}; + + var attr = Object.keys(a).map(function (prop) { + return prop + '="' + a[prop] + '"'; + }).join(' '); + + html += ''; + }); + + return t.openModal(title, html) + .on(CONFIRM_EVENT, function () { + var $form = $('form', $(this)), + valid = true, + values = {}; + + $.each(fields, function (fieldName, field) { + var $field = $('input[name="' + fieldName + '"]', $form), + inputType = $field.attr('type'); + + if (inputType.toLowerCase() === 'checkbox') { + values[fieldName] = $field.is(':checked'); + } else { + values[fieldName] = $.trim($field.val()); + } + // Validate value + if (field.required && values[fieldName] === '') { + valid = false; + t.addErrorOnModalField($field, t.lang.required); + } else if (field.pattern && !field.pattern.test(values[fieldName])) { + valid = false; + t.addErrorOnModalField($field, field.patternError); + } + }); + + if (valid) { + t.restoreRange(); + + if (cmd(values, fields)) { + t.syncCode(); + t.$c.trigger('tbwchange'); + t.closeModal(); + $(this).off(CONFIRM_EVENT); + } + } + }) + .one('tbwcancel', function () { + $(this).off(CONFIRM_EVENT); + t.closeModal(); + }); + }, + addErrorOnModalField: function ($field, err) { + var prefix = this.o.prefix, + $label = $field.parent(); + + $field + .on('change keyup', function () { + $label.removeClass(prefix + 'input-error'); + }); + + $label + .addClass(prefix + 'input-error') + .find('input+span') + .append( + $('', { + class: prefix + 'msg-error', + text: err + }) + ); + }, + + + // Range management + saveRange: function () { + var t = this, + documentSelection = t.doc.getSelection(); + + t.range = null; + + if (documentSelection.rangeCount) { + var savedRange = t.range = documentSelection.getRangeAt(0), + range = t.doc.createRange(), + rangeStart; + range.selectNodeContents(t.$ed[0]); + range.setEnd(savedRange.startContainer, savedRange.startOffset); + rangeStart = (range + '').length; + t.metaRange = { + start: rangeStart, + end: rangeStart + (savedRange + '').length + }; + } + }, + restoreRange: function () { + var t = this, + metaRange = t.metaRange, + savedRange = t.range, + documentSelection = t.doc.getSelection(), + range; + + if (!savedRange) { + return; + } + + if (metaRange && metaRange.start !== metaRange.end) { // Algorithm from http://jsfiddle.net/WeWy7/3/ + var charIndex = 0, + nodeStack = [t.$ed[0]], + node, + foundStart = false, + stop = false; + + range = t.doc.createRange(); + + while (!stop && (node = nodeStack.pop())) { + if (node.nodeType === 3) { + var nextCharIndex = charIndex + node.length; + if (!foundStart && metaRange.start >= charIndex && metaRange.start <= nextCharIndex) { + range.setStart(node, metaRange.start - charIndex); + foundStart = true; + } + if (foundStart && metaRange.end >= charIndex && metaRange.end <= nextCharIndex) { + range.setEnd(node, metaRange.end - charIndex); + stop = true; + } + charIndex = nextCharIndex; + } else { + var cn = node.childNodes, + i = cn.length; + + while (i > 0) { + i -= 1; + nodeStack.push(cn[i]); + } + } + } + } + + documentSelection.removeAllRanges(); + documentSelection.addRange(range || savedRange); + }, + getRangeText: function () { + return this.range + ''; + }, + + updateButtonPaneStatus: function () { + var t = this, + prefix = t.o.prefix, + tags = t.getTagsRecursive(t.doc.getSelection().focusNode), + activeClasses = prefix + 'active-button ' + prefix + 'active'; + + $('.' + prefix + 'active-button', t.$btnPane).removeClass(activeClasses); + $.each(tags, function (i, tag) { + var btnName = t.tagToButton[tag.toLowerCase()], + $btn = $('.' + prefix + btnName + '-button', t.$btnPane); + + if ($btn.length > 0) { + $btn.addClass(activeClasses); + } else { + try { + $btn = $('.' + prefix + 'dropdown .' + prefix + btnName + '-dropdown-button', t.$box); + var dropdownBtnName = $btn.parent().data('dropdown'); + $('.' + prefix + dropdownBtnName + '-button', t.$box).addClass(activeClasses); + } catch (e) { + } + } + }); + }, + getTagsRecursive: function (element, tags) { + var t = this; + tags = tags || []; + + if (element && element.parentNode) { + element = element.parentNode; + } else { + return tags; + } + + var tag = element.tagName; + if (tag === 'DIV') { + return tags; + } + if (tag === 'P' && element.style.textAlign !== '') { + tags.push(element.style.textAlign); + } + + $.each(t.tagHandlers, function (i, tagHandler) { + tags = tags.concat(tagHandler(element, t)); + }); + + tags.push(tag); + + return t.getTagsRecursive(element, tags); + }, + + // Plugins + initPlugins: function () { + var t = this; + t.loadedPlugins = []; + $.each($.trumbowyg.plugins, function (name, plugin) { + if (!plugin.shouldInit || plugin.shouldInit(t)) { + plugin.init(t); + if (plugin.tagHandler) { + t.tagHandlers.push(plugin.tagHandler); + } + t.loadedPlugins.push(plugin); + } + }); + }, + destroyPlugins: function () { + $.each(this.loadedPlugins, function (i, plugin) { + if (plugin.destroy) { + plugin.destroy(); + } + }); + } + }; +})(navigator, window, document, jQuery); diff --git a/public/javascript/trumbowyg.min.js b/public/javascript/trumbowyg.min.js new file mode 100755 index 00000000..a361b363 --- /dev/null +++ b/public/javascript/trumbowyg.min.js @@ -0,0 +1,2 @@ +/** Trumbowyg v2.4.2 - A lightweight WYSIWYG editor - alex-d.github.io/Trumbowyg - License MIT - Author : Alexandre Demode (Alex-D) / alex-d.fr */ +jQuery.trumbowyg={langs:{en:{viewHTML:"View HTML",undo:"Undo",redo:"Redo",formatting:"Formatting",p:"Paragraph",blockquote:"Quote",code:"Code",header:"Header",bold:"Bold",italic:"Italic",strikethrough:"Stroke",underline:"Underline",strong:"Strong",em:"Emphasis",del:"Deleted",superscript:"Superscript",subscript:"Subscript",unorderedList:"Unordered list",orderedList:"Ordered list",insertImage:"Insert Image",link:"Link",createLink:"Insert link",unlink:"Remove link",justifyLeft:"Align Left",justifyCenter:"Align Center",justifyRight:"Align Right",justifyFull:"Align Justify",horizontalRule:"Insert horizontal rule",removeformat:"Remove format",fullscreen:"Fullscreen",close:"Close",submit:"Confirm",reset:"Cancel",required:"Required",description:"Description",title:"Title",text:"Text",target:"Target"}},plugins:{},svgPath:null},function(e,t,n,a){"use strict";a.fn.trumbowyg=function(e,t){var n="trumbowyg";if(e===Object(e)||!e)return this.each(function(){a(this).data(n)||a(this).data(n,new o(this,e))});if(1===this.length)try{var r=a(this).data(n);switch(e){case"execCmd":return r.execCmd(t.cmd,t.param,t.forceCss);case"openModal":return r.openModal(t.title,t.content);case"closeModal":return r.closeModal();case"openModalInsert":return r.openModalInsert(t.title,t.fields,t.callback);case"saveRange":return r.saveRange();case"getRange":return r.range;case"getRangeText":return r.getRangeText();case"restoreRange":return r.restoreRange();case"enable":return r.toggleDisable(!1);case"disable":return r.toggleDisable(!0);case"destroy":return r.destroy();case"empty":return r.empty();case"html":return r.html(t)}}catch(i){}return!1};var o=function(e,o){var r=this,i="trumbowyg-icons";r.doc=e.ownerDocument||n,r.$ta=a(e),r.$c=a(e),o=o||{},null!=o.lang||null!=a.trumbowyg.langs[o.lang]?r.lang=a.extend(!0,{},a.trumbowyg.langs.en,a.trumbowyg.langs[o.lang]):r.lang=a.trumbowyg.langs.en;var s=null!=a.trumbowyg.svgPath?a.trumbowyg.svgPath:o.svgPath;if(r.hasSvg=s!==!1,r.svgPath=r.doc.querySelector("base")?t.location.href.split("#")[0]:"",0===a("#"+i,r.doc).length&&s!==!1){if(null==s)try{throw new Error}catch(l){var d=l.stack.split("\n");for(var c in d)if(d[c].match(/http[s]?:\/\//)){s=d[Number(c)].match(/((http[s]?:\/\/.+\/)([^\/]+\.js))(\?.*)?:/)[1].split("/"),s.pop(),s=s.join("/")+"/ui/icons.svg";break}}var u=r.doc.createElement("div");u.id=i,r.doc.body.insertBefore(u,r.doc.body.childNodes[0]),a.ajax({async:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",dataType:"xml",url:s,data:null,beforeSend:null,complete:null,success:function(e){u.innerHTML=(new XMLSerializer).serializeToString(e.documentElement)}})}var g=r.lang.header,f=function(){return(t.chrome||t.Intl&&Intl.v8BreakIterator)&&"CSS"in t};r.btnsDef={viewHTML:{fn:"toggle"},undo:{isSupported:f,key:"Z"},redo:{isSupported:f,key:"Y"},p:{fn:"formatBlock"},blockquote:{fn:"formatBlock"},h1:{fn:"formatBlock",title:g+" 1"},h2:{fn:"formatBlock",title:g+" 2"},h3:{fn:"formatBlock",title:g+" 3"},h4:{fn:"formatBlock",title:g+" 4"},subscript:{tag:"sub"},superscript:{tag:"sup"},bold:{key:"B",tag:"b"},italic:{key:"I",tag:"i"},underline:{tag:"u"},strikethrough:{tag:"strike"},strong:{fn:"bold",key:"B"},em:{fn:"italic",key:"I"},del:{fn:"strikethrough"},createLink:{key:"K",tag:"a"},unlink:{},insertImage:{},justifyLeft:{tag:"left",forceCss:!0},justifyCenter:{tag:"center",forceCss:!0},justifyRight:{tag:"right",forceCss:!0},justifyFull:{tag:"justify",forceCss:!0},unorderedList:{fn:"insertUnorderedList",tag:"ul"},orderedList:{fn:"insertOrderedList",tag:"ol"},horizontalRule:{fn:"insertHorizontalRule"},removeformat:{},fullscreen:{"class":"trumbowyg-not-disable"},close:{fn:"destroy","class":"trumbowyg-not-disable"},formatting:{dropdown:["p","blockquote","h1","h2","h3","h4"],ico:"p"},link:{dropdown:["createLink","unlink"]}},r.o=a.extend(!0,{},{lang:"en",useComposition:!0,fixedBtnPane:!1,fixedFullWidth:!1,autogrow:!1,prefix:"trumbowyg-",semantic:!0,resetCss:!1,removeformatPasted:!1,tagsToRemove:[],btnsGrps:{design:["bold","italic","underline","strikethrough"],semantic:["strong","em","del"],justify:["justifyLeft","justifyCenter","justifyRight","justifyFull"],lists:["unorderedList","orderedList"]},btns:[["viewHTML"],["undo","redo"],["formatting"],"btnGrp-semantic",["superscript","subscript"],["link"],["insertImage"],"btnGrp-justify","btnGrp-lists",["horizontalRule"],["removeformat"],["fullscreen"]],btnsDef:{},inlineElementsSelector:"a,abbr,acronym,b,caption,cite,code,col,dfn,dir,dt,dd,em,font,hr,i,kbd,li,q,span,strikeout,strong,sub,sup,u",pasteHandlers:[],imgDblClickHandler:function(){var e=a(this),t=e.attr("src"),n="(Base64)";return 0===t.indexOf("data:image")&&(t=n),r.openModalInsert(r.lang.insertImage,{url:{label:"URL",value:t,required:!0},alt:{label:r.lang.description,value:e.attr("alt")}},function(t){return t.src!==n&&e.attr({src:t.src}),e.attr({alt:t.alt}),!0}),!1},plugins:{}},o),r.disabled=r.o.disabled||"TEXTAREA"===e.nodeName&&e.disabled,o.btns?r.o.btns=o.btns:r.o.semantic||(r.o.btns[4]="btnGrp-design"),a.each(r.o.btnsDef,function(e,t){r.addBtnDef(e,t)}),r.eventNamespace="trumbowyg-event",r.keys=[],r.tagToButton={},r.tagHandlers=[],r.pasteHandlers=[].concat(r.o.pasteHandlers),r.init()};o.prototype={init:function(){var e=this;e.height=e.$ta.height(),e.initPlugins();try{e.doc.execCommand("enableObjectResizing",!1,!1),e.doc.execCommand("defaultParagraphSeparator",!1,"p")}catch(t){}e.buildEditor(),e.buildBtnPane(),e.fixedBtnPaneEvents(),e.buildOverlay(),setTimeout(function(){e.disabled&&e.toggleDisable(!0),e.$c.trigger("tbwinit")})},addBtnDef:function(e,t){this.btnsDef[e]=t},buildEditor:function(){var e=this,n=e.o.prefix,o="";e.$box=a("",{"class":n+"box "+n+"editor-visible "+n+e.o.lang+" trumbowyg"}),e.isTextarea=e.$ta.is("textarea"),e.isTextarea?(o=e.$ta.val(),e.$ed=a(""),e.$box.insertAfter(e.$ta).append(e.$ed,e.$ta)):(e.$ed=e.$ta,o=e.$ed.html(),e.$ta=a("",{name:e.$ta.attr("id"),height:e.height}).val(o),e.$box.insertAfter(e.$ed).append(e.$ta,e.$ed),e.syncCode()),e.$ta.addClass(n+"textarea").attr("tabindex",-1),e.$ed.addClass(n+"editor").attr({contenteditable:!0,dir:e.lang._dir||"ltr"}).html(o),e.o.tabindex&&e.$ed.attr("tabindex",e.o.tabindex),e.$c.is("[placeholder]")&&e.$ed.attr("placeholder",e.$c.attr("placeholder")),e.o.resetCss&&e.$ed.addClass(n+"reset-css"),e.o.autogrow||e.$ta.add(e.$ed).css({height:e.height}),e.semanticCode();var r,i=!1,s=!1;e.$ed.on("dblclick","img",e.o.imgDblClickHandler).on("keydown",function(t){if(s=e.o.useComposition&&229===t.which,t.ctrlKey){i=!0;var n=e.keys[String.fromCharCode(t.which).toUpperCase()];try{return e.execCmd(n.fn,n.param),!1}catch(a){}}}).on("keyup input",function(t){t.which>=37&&t.which<=40||(!t.ctrlKey||89!==t.which&&90!==t.which?i||17===t.which||s||(e.semanticCode(!1,13===t.which),e.$c.trigger("tbwchange")):e.$c.trigger("tbwchange"),setTimeout(function(){i=!1},200))}).on("mouseup keydown keyup",function(){clearTimeout(r),r=setTimeout(function(){e.updateButtonPaneStatus()},50)}).on("focus blur",function(t){e.$c.trigger("tbw"+t.type),"blur"===t.type&&a("."+n+"active-button",e.$btnPane).removeClass(n+"active-button "+n+"active")}).on("cut",function(){setTimeout(function(){e.semanticCode(!1,!0),e.$c.trigger("tbwchange")},0)}).on("paste",function(n){if(e.o.removeformatPasted){n.preventDefault();try{var o=t.clipboardData.getData("Text");try{e.doc.selection.createRange().pasteHTML(o)}catch(r){e.doc.getSelection().getRangeAt(0).insertNode(e.doc.createTextNode(o))}}catch(i){e.execCmd("insertText",(n.originalEvent||n).clipboardData.getData("text/plain"))}}a.each(e.pasteHandlers,function(e,t){t(n)}),setTimeout(function(){e.semanticCode(!1,!0),e.$c.trigger("tbwpaste",n)},0)}),e.$ta.on("keyup paste",function(){e.$c.trigger("tbwchange")}),e.$box.on("keydown",function(t){return 27===t.which&&1===a("."+n+"modal-box",e.$box).length?(e.closeModal(),!1):void 0})},buildBtnPane:function(){var e=this,t=e.o.prefix,n=e.$btnPane=a("",{"class":t+"button-pane"});a.each(e.o.btns,function(o,r){try{var i=r.split("btnGrp-");null!=i[1]&&(r=e.o.btnsGrps[i[1]])}catch(s){}a.isArray(r)||(r=[r]);var l=a("",{"class":t+"button-group "+(r.indexOf("fullscreen")>=0?t+"right":"")});a.each(r,function(t,n){try{var a;e.isSupportedBtn(n)&&(a=e.buildBtn(n)),l.append(a)}catch(o){}}),n.append(l)}),e.$box.prepend(n)},buildBtn:function(e){var t=this,n=t.o.prefix,o=t.btnsDef[e],r=o.dropdown,i=null!=o.hasIcon?o.hasIcon:!0,s=t.lang[e]||e,l=a("",{type:"button","class":n+e+"-button "+(o["class"]||"")+(i?"":" "+n+"textual-button"),html:t.hasSvg&&i?'':o.text||o.title||t.lang[e]||e,title:(o.title||o.text||s)+(o.key?" (Ctrl + "+o.key+")":""),tabindex:-1,mousedown:function(){return(!r||a("."+e+"-"+n+"dropdown",t.$box).is(":hidden"))&&a("body",t.doc).trigger("mousedown"),!t.$btnPane.hasClass(n+"disable")||a(this).hasClass(n+"active")||a(this).hasClass(n+"not-disable")?(t.execCmd((r?"dropdown":!1)||o.fn||e,o.param||e,o.forceCss||!1),!1):!1}});if(r){l.addClass(n+"open-dropdown");var d=n+"dropdown",c=a("",{"class":d+"-"+e+" "+d+" "+n+"fixed-top","data-dropdown":e});a.each(r,function(e,n){t.btnsDef[n]&&t.isSupportedBtn(n)&&c.append(t.buildSubBtn(n))}),t.$box.append(c.hide())}else o.key&&(t.keys[o.key]={fn:o.fn||e,param:o.param||e});return r||(t.tagToButton[(o.tag||e).toLowerCase()]=e),l},buildSubBtn:function(e){var t=this,n=t.o.prefix,o=t.btnsDef[e],r=null!=o.hasIcon?o.hasIcon:!0;return o.key&&(t.keys[o.key]={fn:o.fn||e,param:o.param||e}),t.tagToButton[(o.tag||e).toLowerCase()]=e,a("",{type:"button","class":n+e+"-dropdown-button"+(o.ico?" "+n+o.ico+"-button":""),html:t.hasSvg&&r?''+(o.text||o.title||t.lang[e]||e):o.text||o.title||t.lang[e]||e,title:o.key?" (Ctrl + "+o.key+")":null,style:o.style||null,mousedown:function(){return a("body",t.doc).trigger("mousedown"),t.execCmd(o.fn||e,o.param||e,o.forceCss||!1),!1}})},isSupportedBtn:function(e){try{return this.btnsDef[e].isSupported()}catch(t){}return!0},buildOverlay:function(){var e=this;return e.$overlay=a("",{"class":e.o.prefix+"overlay"}).css({top:e.$btnPane.outerHeight(),height:e.$ed.outerHeight()+1+"px"}).appendTo(e.$box),e.$overlay},showOverlay:function(){var e=this;a(t).trigger("scroll"),e.$overlay.fadeIn(200),e.$box.addClass(e.o.prefix+"box-blur")},hideOverlay:function(){var e=this;e.$overlay.fadeOut(50),e.$box.removeClass(e.o.prefix+"box-blur")},fixedBtnPaneEvents:function(){var e=this,n=e.o.fixedFullWidth,o=e.$box;e.o.fixedBtnPane&&(e.isFixed=!1,a(t).on("scroll."+e.eventNamespace+" resize."+e.eventNamespace,function(){if(o){e.syncCode();var r=a(t).scrollTop(),i=o.offset().top+1,s=e.$btnPane,l=s.outerHeight()-2;r-i>0&&r-i-e.height<0?(e.isFixed||(e.isFixed=!0,s.css({position:"fixed",top:0,left:n?"0":"auto",zIndex:7}),a([e.$ta,e.$ed]).css({marginTop:s.height()})),s.css({width:n?"100%":o.width()-1+"px"}),a("."+e.o.prefix+"fixed-top",o).css({position:n?"fixed":"absolute",top:n?l:l+(r-i)+"px",zIndex:15})):e.isFixed&&(e.isFixed=!1,s.removeAttr("style"),a([e.$ta,e.$ed]).css({marginTop:0}),a("."+e.o.prefix+"fixed-top",o).css({position:"absolute",top:l}))}}))},toggleDisable:function(e){var t=this,n=t.o.prefix;t.disabled=e,e?t.$ta.attr("disabled",!0):t.$ta.removeAttr("disabled"),t.$box.toggleClass(n+"disabled",e),t.$ed.attr("contenteditable",!e)},destroy:function(){var e=this,n=e.o.prefix,o=e.height;e.isTextarea?e.$box.after(e.$ta.css({height:o}).val(e.html()).removeClass(n+"textarea").show()):e.$box.after(e.$ed.css({height:o}).removeClass(n+"editor").removeAttr("contenteditable").html(e.html()).show()),e.$ed.off("dblclick","img"),e.destroyPlugins(),e.$box.remove(),e.$c.removeData("trumbowyg"),a("body").removeClass(n+"body-fullscreen"),e.$c.trigger("tbwclose"),a(t).off("scroll."+e.eventNamespace+" resize."+e.eventNamespace)},empty:function(){this.$ta.val(""),this.syncCode(!0)},toggle:function(){var e=this,t=e.o.prefix;e.semanticCode(!1,!0),setTimeout(function(){e.doc.activeElement.blur(),e.$box.toggleClass(t+"editor-hidden "+t+"editor-visible"),e.$btnPane.toggleClass(t+"disable"),a("."+t+"viewHTML-button",e.$btnPane).toggleClass(t+"active"),e.$box.hasClass(t+"editor-visible")?e.$ta.attr("tabindex",-1):e.$ta.removeAttr("tabindex")},0)},dropdown:function(e){var n=this,o=n.doc,r=n.o.prefix,i=a("[data-dropdown="+e+"]",n.$box),s=a("."+r+e+"-button",n.$btnPane),l=i.is(":hidden");if(a("body",o).trigger("mousedown"),l){var d=s.offset().left;s.addClass(r+"active"),i.css({position:"absolute",top:s.offset().top-n.$btnPane.offset().top+s.outerHeight(),left:n.o.fixedFullWidth&&n.isFixed?d+"px":d-n.$btnPane.offset().left+"px"}).show(),a(t).trigger("scroll"),a("body",o).on("mousedown."+n.eventNamespace,function(){a("."+r+"dropdown",o).hide(),a("."+r+"active",o).removeClass(r+"active"),a("body",o).off("mousedown."+n.eventNamespace)})}},html:function(e){var t=this;return null!=e?(t.$ta.val(e),t.syncCode(!0),t):t.$ta.val()},syncTextarea:function(){var e=this;e.$ta.val(e.$ed.text().trim().length>0||e.$ed.find("hr,img,embed,iframe,input").length>0?e.$ed.html():"")},syncCode:function(e){var t=this;!e&&t.$ed.is(":visible")?t.syncTextarea():t.$ed.html(t.$ta.val()),t.o.autogrow&&(t.height=t.$ed.height(),t.height!==t.$ta.css("height")&&(t.$ta.css({height:t.height}),t.$c.trigger("tbwresize")))},semanticCode:function(e,t){var n=this;if(n.saveRange(),n.syncCode(e),a(n.o.tagsToRemove.join(","),n.$ed).remove(),n.o.semantic){if(n.semanticTag("b","strong"),n.semanticTag("i","em"),t){var o=n.o.inlineElementsSelector,r=":not("+o+")";n.$ed.contents().filter(function(){return 3===this.nodeType&&this.nodeValue.trim().length>0}).wrap("");var i=function(e){if(0!==e.length){var t=e.nextUntil(r).addBack().wrapAll("").parent(),n=t.nextAll(o).first();t.next("br").remove(),i(n)}};i(n.$ed.children(o).first()),n.semanticTag("div","p",!0),n.$ed.find("p").filter(function(){return n.range&&this===n.range.startContainer?!1:0===a(this).text().trim().length&&0===a(this).children().not("br,span").length}).contents().unwrap(),a("[data-tbw]",n.$ed).contents().unwrap(),n.$ed.find("p:empty").remove()}n.restoreRange(),n.syncTextarea()}},semanticTag:function(e,t,n){a(e,this.$ed).each(function(){var e=a(this);e.wrap("<"+t+"/>"),n&&a.each(e.prop("attributes"),function(){e.parent().attr(this.name,this.value)}),e.contents().unwrap()})},createLink:function(){for(var e,t,n,o=this,r=o.doc.getSelection(),i=r.focusNode;["A","DIV"].indexOf(i.nodeName)<0;)i=i.parentNode;if(i&&"A"===i.nodeName){var s=a(i);e=s.attr("href"),t=s.attr("title"),n=s.attr("target");var l=o.doc.createRange();l.selectNode(i),r.addRange(l)}o.saveRange(),o.openModalInsert(o.lang.createLink,{url:{label:"URL",required:!0,value:e},title:{label:o.lang.title,value:t},text:{label:o.lang.text,value:o.getRangeText()},target:{label:o.lang.target,value:n}},function(e){var t=a(['',e.text,""].join(""));return e.title.length>0&&t.attr("title",e.title),e.target.length>0&&t.attr("target",e.target),o.range.deleteContents(),o.range.insertNode(t[0]),!0})},unlink:function(){var e=this,t=e.doc.getSelection(),n=t.focusNode;if(t.isCollapsed){for(;["A","DIV"].indexOf(n.nodeName)<0;)n=n.parentNode;if(n&&"A"===n.nodeName){var a=e.doc.createRange();a.selectNode(n),t.addRange(a)}}e.execCmd("unlink",void 0,void 0,!0)},insertImage:function(){var e=this;e.saveRange(),e.openModalInsert(e.lang.insertImage,{url:{label:"URL",required:!0},alt:{label:e.lang.description,value:e.getRangeText()}},function(t){return e.execCmd("insertImage",t.url),a('img[src="'+t.url+'"]:not([alt])',e.$box).attr("alt",t.alt),!0})},fullscreen:function(){var e,n=this,o=n.o.prefix,r=o+"fullscreen";n.$box.toggleClass(r),e=n.$box.hasClass(r),a("body").toggleClass(o+"body-fullscreen",e),a(t).trigger("scroll"),n.$c.trigger("tbw"+(e?"open":"close")+"fullscreen")},execCmd:function(t,n,a,o){var r=this;o=!!o||"","dropdown"!==t&&r.$ed.focus();try{r.doc.execCommand("styleWithCSS",!1,a||!1)}catch(i){}try{r[t+o](n)}catch(i){try{t(n)}catch(s){"insertHorizontalRule"===t?n=void 0:"formatBlock"!==t||-1===e.userAgent.indexOf("MSIE")&&-1===e.appVersion.indexOf("Trident/")||(n="<"+n+">"),r.doc.execCommand(t,!1,n),r.syncCode(),r.semanticCode(!1,!0)}"dropdown"!==t&&(r.updateButtonPaneStatus(),r.$c.trigger("tbwchange"))}},openModal:function(e,n){var o=this,r=o.o.prefix;if(a("."+r+"modal-box",o.$box).length>0)return!1;o.saveRange(),o.showOverlay(),o.$btnPane.addClass(r+"disable");var i=a("",{"class":r+"modal "+r+"fixed-top"}).css({top:o.$btnPane.height()}).appendTo(o.$box);o.$overlay.one("click",function(){return i.trigger("tbwcancel"),!1});var s=a("",{action:"",html:n}).on("submit",function(){return i.trigger("tbwconfirm"),!1}).on("reset",function(){return i.trigger("tbwcancel"),!1}),l=a("",{"class":r+"modal-box",html:s}).css({top:"-"+o.$btnPane.outerHeight()+"px",opacity:0}).appendTo(i).animate({top:0,opacity:1},100);return a("",{text:e,"class":r+"modal-title"}).prependTo(l),i.height(l.outerHeight()+10),a("input:first",l).focus(),o.buildModalBtn("submit",l),o.buildModalBtn("reset",l),a(t).trigger("scroll"),i},buildModalBtn:function(e,t){var n=this,o=n.o.prefix;return a("",{"class":o+"modal-button "+o+"modal-"+e,type:e,text:n.lang[e]||e}).appendTo(a("form",t))},closeModal:function(){var e=this,t=e.o.prefix;e.$btnPane.removeClass(t+"disable"),e.$overlay.off();var n=a("."+t+"modal-box",e.$box);n.animate({top:"-"+n.height()},100,function(){n.parent().remove(),e.hideOverlay()}),e.restoreRange()},openModalInsert:function(e,t,n){var o=this,r=o.o.prefix,i=o.lang,s="",l="tbwconfirm";return a.each(t,function(e,t){var n=t.label,a=t.name||e,o=t.attributes||{},l=Object.keys(o).map(function(e){return e+'="'+o[e]+'"'}).join(" ");s+='"}),o.openModal(e,s).on(l,function(){var e=a("form",a(this)),r=!0,i={};a.each(t,function(t,n){var s=a('input[name="'+t+'"]',e),l=s.attr("type");"checkbox"===l.toLowerCase()?i[t]=s.is(":checked"):i[t]=a.trim(s.val()),n.required&&""===i[t]?(r=!1,o.addErrorOnModalField(s,o.lang.required)):n.pattern&&!n.pattern.test(i[t])&&(r=!1,o.addErrorOnModalField(s,n.patternError))}),r&&(o.restoreRange(),n(i,t)&&(o.syncCode(),o.$c.trigger("tbwchange"),o.closeModal(),a(this).off(l)))}).one("tbwcancel",function(){a(this).off(l),o.closeModal()})},addErrorOnModalField:function(e,t){var n=this.o.prefix,o=e.parent();e.on("change keyup",function(){o.removeClass(n+"input-error")}),o.addClass(n+"input-error").find("input+span").append(a("",{"class":n+"msg-error",text:t}))},saveRange:function(){var e=this,t=e.doc.getSelection();if(e.range=null,t.rangeCount){var n,a=e.range=t.getRangeAt(0),o=e.doc.createRange();o.selectNodeContents(e.$ed[0]),o.setEnd(a.startContainer,a.startOffset),n=(o+"").length,e.metaRange={start:n,end:n+(a+"").length}}},restoreRange:function(){var e,t=this,n=t.metaRange,a=t.range,o=t.doc.getSelection();if(a){if(n&&n.start!==n.end){var r,i=0,s=[t.$ed[0]],l=!1,d=!1;for(e=t.doc.createRange();!d&&(r=s.pop());)if(3===r.nodeType){var c=i+r.length;!l&&n.start>=i&&n.start<=c&&(e.setStart(r,n.start-i),l=!0),l&&n.end>=i&&n.end<=c&&(e.setEnd(r,n.end-i),d=!0),i=c}else for(var u=r.childNodes,g=u.length;g>0;)g-=1,s.push(u[g])}o.removeAllRanges(),o.addRange(e||a)}},getRangeText:function(){return this.range+""},updateButtonPaneStatus:function(){var e=this,t=e.o.prefix,n=e.getTagsRecursive(e.doc.getSelection().focusNode),o=t+"active-button "+t+"active";a("."+t+"active-button",e.$btnPane).removeClass(o),a.each(n,function(n,r){var i=e.tagToButton[r.toLowerCase()],s=a("."+t+i+"-button",e.$btnPane);if(s.length>0)s.addClass(o);else try{s=a("."+t+"dropdown ."+t+i+"-dropdown-button",e.$box);var l=s.parent().data("dropdown");a("."+t+l+"-button",e.$box).addClass(o)}catch(d){}})},getTagsRecursive:function(e,t){var n=this;if(t=t||[],!e||!e.parentNode)return t;e=e.parentNode;var o=e.tagName;return"DIV"===o?t:("P"===o&&""!==e.style.textAlign&&t.push(e.style.textAlign),a.each(n.tagHandlers,function(a,o){t=t.concat(o(e,n))}),t.push(o),n.getTagsRecursive(e,t))},initPlugins:function(){var e=this;e.loadedPlugins=[],a.each(a.trumbowyg.plugins,function(t,n){(!n.shouldInit||n.shouldInit(e))&&(n.init(e),n.tagHandler&&e.tagHandlers.push(n.tagHandler),e.loadedPlugins.push(n))})},destroyPlugins:function(){a.each(this.loadedPlugins,function(e,t){t.destroy&&t.destroy()})}}}(navigator,window,document,jQuery); \ No newline at end of file diff --git a/public/stylesheets/raw/icons.svg b/public/stylesheets/raw/icons.svg new file mode 100755 index 00000000..5c0f4f64 --- /dev/null +++ b/public/stylesheets/raw/icons.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/stylesheets/raw/styles.css b/public/stylesheets/raw/styles.css index 5b83e69b..c2bcf056 100644 --- a/public/stylesheets/raw/styles.css +++ b/public/stylesheets/raw/styles.css @@ -8,7 +8,7 @@ textarea{resize:none;padding:0;} .sprites-after:after{background-image:url("../../images/sprites.png");content:"";height:17px;width:16px;margin:0.45em 0.2em;display:inline-block;float:right;} .hidden-message{display:none;} #header,#tabs{min-width:1175px;} -#header{color:#bababa;font-size:0.8em;position:fixed;z-index:100;top:0;left:0;right:0;height:2.5em;line-height:2.5em;width:100%;box-shadow:0 1px 2px rgba(0, 0, 0, 0.5);background-color: #333;} +#header{color:#bababa;font-size:0.8em;height:2.5em;line-height:2.5em;background-color: #333;} #header a{color:#bababa;text-decoration:none;} #header a:hover{color:#fff;} #site-title{position:absolute;left:5px;margin:0 0.25em;color:#fff;font-size:1.5em;line-height:1.5em;} @@ -25,7 +25,6 @@ textarea{resize:none;padding:0;} #site-languages ul{list-style:none;margin:0px;padding:0px;} #site-languages li{list-style:none;display:inline;margin:0px 5px;padding:0px;} #site-languages li a.selected{color:white;} -#wrapper{position:absolute;width:100%;top:1.75em;} #tabs{min-height:520px;display:none;border:0px;} #error-message{margin:0;padding:1em;} ul.navigation{border-top:0px;border-left:0px;border-right:0px;} @@ -207,7 +206,6 @@ button[disabled], button[disabled]:hover, button[disabled]:active{color:#666 !im #map-admin ul, #map-admin li{list-style:none;margin:0px;padding:0px;} #map-admin li{display:inline;margin:0px 5px;} #map-admin label, #map-admin input, #map-admin textarea {display:block;} -#map-admin .resizable-textarea {width:600px;} #map-admin p.citation{text-indent:-2em;padding-left:2em;font-size:0.75em;} #admin-api-list {font-size:11px;} #map-admin a.citation-delete:before{background-position:-260px -284px;margin-top:0.2em;} diff --git a/public/stylesheets/raw/trumbowyg.css b/public/stylesheets/raw/trumbowyg.css new file mode 100755 index 00000000..eb8da7cf --- /dev/null +++ b/public/stylesheets/raw/trumbowyg.css @@ -0,0 +1,588 @@ +/** + * Trumbowyg v2.4.2 - A lightweight WYSIWYG editor + * Default stylesheet for Trumbowyg editor + * ------------------------ + * @link http://alex-d.github.io/Trumbowyg + * @license MIT + * @author Alexandre Demode (Alex-D) + * Twitter : @AlexandreDemode + * Website : alex-d.fr + */ + +#trumbowyg-icons { + overflow: hidden; + visibility: hidden; + height: 0; + width: 0; } + #trumbowyg-icons svg { + height: 0; + width: 0; } + +.trumbowyg-box *, +.trumbowyg-box *::before, +.trumbowyg-box *::after { + box-sizing: border-box; } + +.trumbowyg-box svg { + width: 17px; + height: 100%; + fill: #222; } + +.trumbowyg-box, +.trumbowyg-editor { + display: block; + position: relative; + border: 1px solid #DDD; + width: 600px; + min-height: 200px; } + +.trumbowyg-editor p { + margin:0px; + padding:0px; +} + +.trumbowyg-box .trumbowyg-editor { + margin: 0 auto; } + +.trumbowyg-box.trumbowyg-fullscreen { + background: #FEFEFE; + border: none !important; } + +.trumbowyg-editor, +.trumbowyg-textarea { + position: relative; + box-sizing: border-box; + padding: 10px; + min-height: 200px; + width: 100%; + border-style: none; + resize: none; + outline: none; + overflow: auto; } + +.trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-box-blur .trumbowyg-editor::before { + color: transparent !important; + text-shadow: 0 0 7px #333; } + @media screen and (min-width: 0 \0 ) { + .trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-box-blur .trumbowyg-editor::before { + color: rgba(200, 200, 200, 0.6) !important; } } + @supports (-ms-accelerator: true) { + .trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-box-blur .trumbowyg-editor::before { + color: rgba(200, 200, 200, 0.6) !important; } } + +.trumbowyg-box-blur .trumbowyg-editor img, +.trumbowyg-box-blur .trumbowyg-editor hr { + opacity: 0.2; } + +.trumbowyg-textarea { + position: relative; + display: block; + overflow: auto; + border: none; + white-space: normal; + font-size: 14px; + font-family: "Inconsolata", "Consolas", "Courier", "Courier New", sans-serif; + line-height: 18px; } + +.trumbowyg-box.trumbowyg-editor-visible .trumbowyg-textarea { + height: 1px !important; + width: 25%; + min-height: 0 !important; + padding: 0 !important; + background: none; + opacity: 0 !important; } + +.trumbowyg-box.trumbowyg-editor-hidden .trumbowyg-textarea { + display: block; } + +.trumbowyg-box.trumbowyg-editor-hidden .trumbowyg-editor { + display: none; } + +.trumbowyg-box.trumbowyg-disabled .trumbowyg-textarea { + opacity: 0.8; + background: none; } + +.trumbowyg-editor[contenteditable=true]:empty:not(:focus)::before { + content: attr(placeholder); + color: #999; + pointer-events: none; } + +.trumbowyg-button-pane { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + width: 100%; + min-height: 36px; + background: #ecf0f1; + border-bottom: 1px solid #d7e0e2; + margin: 0; + padding: 0 5px; + list-style-type: none; + line-height: 10px; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; } + .trumbowyg-button-pane::after { + content: " "; + display: block; + position: absolute; + top: 36px; + left: 0; + right: 0; + width: 100%; + height: 1px; + background: #d7e0e2; } + .trumbowyg-button-pane .trumbowyg-button-group { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-flow: row wrap; + flex-flow: row wrap; } + .trumbowyg-button-pane .trumbowyg-button-group .trumbowyg-fullscreen-button svg { + color: transparent; } + .trumbowyg-button-pane .trumbowyg-button-group:not(:empty) + .trumbowyg-button-group::before { + content: " "; + display: block; + width: 1px; + background: #d7e0e2; + margin: 0 5px; + height: 35px; } + .trumbowyg-button-pane button { + display: block; + position: relative; + width: 35px; + height: 35px; + padding: 1px 6px !important; + margin-bottom: 1px; + overflow: hidden; + border: none; + cursor: pointer; + background: none; + -webkit-transition: background-color 150ms, opacity 150ms; + transition: background-color 150ms, opacity 150ms; } + .trumbowyg-button-pane button.trumbowyg-textual-button { + width: auto; + line-height: 35px; } + .trumbowyg-button-pane.trumbowyg-disable button:not(.trumbowyg-not-disable):not(.trumbowyg-active), + .trumbowyg-disabled .trumbowyg-button-pane button:not(.trumbowyg-not-disable):not(.trumbowyg-viewHTML-button) { + opacity: 0.2; + cursor: default; } + .trumbowyg-button-pane.trumbowyg-disable .trumbowyg-button-group::before, + .trumbowyg-disabled .trumbowyg-button-pane .trumbowyg-button-group::before { + background: #e3e9eb; } + .trumbowyg-button-pane button:not(.trumbowyg-disable):hover, + .trumbowyg-button-pane button:not(.trumbowyg-disable):focus, + .trumbowyg-button-pane button.trumbowyg-active { + background-color: #FFF; + outline: none; } + .trumbowyg-button-pane .trumbowyg-open-dropdown::after { + display: block; + content: " "; + position: absolute; + top: 25px; + right: 3px; + height: 0; + width: 0; + border: 3px solid transparent; + border-top-color: #555; } + .trumbowyg-button-pane .trumbowyg-open-dropdown.trumbowyg-textual-button { + padding-left: 10px !important; + padding-right: 18px !important; } + .trumbowyg-button-pane .trumbowyg-open-dropdown.trumbowyg-textual-button::after { + top: 17px; + right: 7px; } + .trumbowyg-button-pane .trumbowyg-right { + margin-left: auto; } + .trumbowyg-button-pane .trumbowyg-right::before { + display: none !important; } + +.trumbowyg-dropdown { + width: 200px; + border: 1px solid #ecf0f1; + padding: 5px 0; + border-top: none; + background: #FFF; + margin-left: -1px; + box-shadow: rgba(0, 0, 0, 0.1) 0 2px 3px; } + .trumbowyg-dropdown button { + display: block; + width: 100%; + height: 35px; + line-height: 35px; + text-decoration: none; + background: #FFF; + padding: 0 10px; + color: #333 !important; + border: none; + cursor: pointer; + text-align: left; + font-size: 15px; + -webkit-transition: all 150ms; + transition: all 150ms; } + .trumbowyg-dropdown button:hover, .trumbowyg-dropdown button:focus { + background: #ecf0f1; } + .trumbowyg-dropdown button svg { + float: left; + margin-right: 14px; } + +/* Modal box */ +.trumbowyg-modal { + position: absolute; + top: 0; + left: 50%; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); + max-width: 520px; + width: 100%; + height: 350px; + z-index: 11; + overflow: hidden; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; } + +.trumbowyg-modal-box { + position: absolute; + top: 0; + left: 50%; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); + max-width: 500px; + width: calc(100% - 20px); + padding-bottom: 45px; + z-index: 1; + background-color: #FFF; + text-align: center; + font-size: 14px; + box-shadow: rgba(0, 0, 0, 0.2) 0 2px 3px; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; } + .trumbowyg-modal-box .trumbowyg-modal-title { + font-size: 24px; + font-weight: bold; + margin: 0 0 20px; + padding: 15px 0 13px; + display: block; + border-bottom: 1px solid #EEE; + color: #333; + background: #fbfcfc; } + .trumbowyg-modal-box .trumbowyg-progress { + width: 100%; + height: 3px; + position: absolute; + top: 58px; } + .trumbowyg-modal-box .trumbowyg-progress .trumbowyg-progress-bar { + background: #2BC06A; + height: 100%; + -webkit-transition: width 150ms linear; + transition: width 150ms linear; } + .trumbowyg-modal-box label { + display: block; + position: relative; + margin: 15px 12px; + height: 29px; + line-height: 29px; + overflow: hidden; } + .trumbowyg-modal-box label .trumbowyg-input-infos { + display: block; + text-align: left; + height: 25px; + line-height: 25px; + -webkit-transition: all 150ms; + transition: all 150ms; } + .trumbowyg-modal-box label .trumbowyg-input-infos span { + display: block; + color: #69878f; + background-color: #fbfcfc; + border: 1px solid #DEDEDE; + padding: 0 7px; + width: 150px; } + .trumbowyg-modal-box label .trumbowyg-input-infos span.trumbowyg-msg-error { + color: #e74c3c; } + .trumbowyg-modal-box label.trumbowyg-input-error input, + .trumbowyg-modal-box label.trumbowyg-input-error textarea { + border: 1px solid #e74c3c; } + .trumbowyg-modal-box label.trumbowyg-input-error .trumbowyg-input-infos { + margin-top: -27px; } + .trumbowyg-modal-box label input { + position: absolute; + top: 0; + right: 0; + height: 27px; + line-height: 27px; + border: 1px solid #DEDEDE; + background: #fff; + font-size: 14px; + max-width: 330px; + width: 70%; + padding: 0 7px; + -webkit-transition: all 150ms; + transition: all 150ms; } + .trumbowyg-modal-box label input:hover, .trumbowyg-modal-box label input:focus { + outline: none; + border: 1px solid #95a5a6; } + .trumbowyg-modal-box label input:focus { + background: #fbfcfc; } + .trumbowyg-modal-box .error { + margin-top: 25px; + display: block; + color: red; } + .trumbowyg-modal-box .trumbowyg-modal-button { + position: absolute; + bottom: 10px; + right: 0; + text-decoration: none; + color: #FFF; + display: block; + width: 100px; + height: 35px; + line-height: 33px; + margin: 0 10px; + background-color: #333; + border: none; + cursor: pointer; + font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif; + font-size: 16px; + -webkit-transition: all 150ms; + transition: all 150ms; } + .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit { + right: 110px; + background: #2bc06a; } + .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:hover, .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:focus { + background: #40d47e; + outline: none; } + .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:active { + background: #25a25a; } + .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset { + color: #555; + background: #e6e6e6; } + .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:hover, .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:focus { + background: #fbfbfb; + outline: none; } + .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:active { + background: #d5d5d5; } + +.trumbowyg-overlay { + position: absolute; + background-color: rgba(255, 255, 255, 0.5); + width: 100%; + left: 0; + display: none; + z-index: 10; } + +/** + * Fullscreen + */ +body.trumbowyg-body-fullscreen { + overflow: hidden; } + +.trumbowyg-fullscreen { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + z-index: 99999; } + .trumbowyg-fullscreen.trumbowyg-box, + .trumbowyg-fullscreen .trumbowyg-editor { + border: none; } + .trumbowyg-fullscreen .trumbowyg-editor, + .trumbowyg-fullscreen .trumbowyg-textarea { + height: calc(100% - 37px) !important; + overflow: auto; } + .trumbowyg-fullscreen .trumbowyg-overlay { + height: 100% !important; } + .trumbowyg-fullscreen .trumbowyg-button-group .trumbowyg-fullscreen-button svg { + color: #222; + fill: transparent; } + +.trumbowyg-editor { + /* + * lset for resetCss option + */ } + .trumbowyg-editor object, + .trumbowyg-editor embed, + .trumbowyg-editor video, + .trumbowyg-editor img { + max-width: 100%; } + .trumbowyg-editor video, + .trumbowyg-editor img { + height: auto; } + .trumbowyg-editor img { + cursor: move; } + .trumbowyg-editor.trumbowyg-reset-css { + background: #FEFEFE !important; + font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif !important; + font-size: 14px !important; + line-height: 1.45em !important; + white-space: normal !important; + color: #333; } + .trumbowyg-editor.trumbowyg-reset-css a { + color: #15c !important; + text-decoration: underline !important; } + .trumbowyg-editor.trumbowyg-reset-css div, + .trumbowyg-editor.trumbowyg-reset-css p, + .trumbowyg-editor.trumbowyg-reset-css ul, + .trumbowyg-editor.trumbowyg-reset-css ol, + .trumbowyg-editor.trumbowyg-reset-css blockquote { + box-shadow: none !important; + background: none !important; + margin: 0 !important; + margin-bottom: 15px !important; + line-height: 1.4em !important; + font-family: "Trebuchet MS", Helvetica, Verdana, sans-serif !important; + font-size: 14px !important; + border: none; } + .trumbowyg-editor.trumbowyg-reset-css iframe, + .trumbowyg-editor.trumbowyg-reset-css object, + .trumbowyg-editor.trumbowyg-reset-css hr { + margin-bottom: 15px !important; } + .trumbowyg-editor.trumbowyg-reset-css blockquote { + margin-left: 32px !important; + font-style: italic !important; + color: #555; } + .trumbowyg-editor.trumbowyg-reset-css ul, + .trumbowyg-editor.trumbowyg-reset-css ol { + padding-left: 20px !important; } + .trumbowyg-editor.trumbowyg-reset-css ul ul, + .trumbowyg-editor.trumbowyg-reset-css ol ol, + .trumbowyg-editor.trumbowyg-reset-css ul ol, + .trumbowyg-editor.trumbowyg-reset-css ol ul { + border: none; + margin: 2px !important; + padding: 0 !important; + padding-left: 24px !important; } + .trumbowyg-editor.trumbowyg-reset-css hr { + display: block; + height: 1px; + border: none; + border-top: 1px solid #CCC; } + .trumbowyg-editor.trumbowyg-reset-css h1, + .trumbowyg-editor.trumbowyg-reset-css h2, + .trumbowyg-editor.trumbowyg-reset-css h3, + .trumbowyg-editor.trumbowyg-reset-css h4 { + color: #111; + background: none; + margin: 0 !important; + padding: 0 !important; + font-weight: bold; } + .trumbowyg-editor.trumbowyg-reset-css h1 { + font-size: 32px !important; + line-height: 38px !important; + margin-bottom: 20px !important; } + .trumbowyg-editor.trumbowyg-reset-css h2 { + font-size: 26px !important; + line-height: 34px !important; + margin-bottom: 15px !important; } + .trumbowyg-editor.trumbowyg-reset-css h3 { + font-size: 22px !important; + line-height: 28px !important; + margin-bottom: 7px !important; } + .trumbowyg-editor.trumbowyg-reset-css h4 { + font-size: 16px !important; + line-height: 22px !important; + margin-bottom: 7px !important; } + +/* + * Dark theme + */ +.trumbowyg-dark .trumbowyg-textarea { + background: #111; + color: #ddd; } + +.trumbowyg-dark .trumbowyg-box { + border: 1px solid #343434; } + .trumbowyg-dark .trumbowyg-box.trumbowyg-fullscreen { + background: #111; } + .trumbowyg-dark .trumbowyg-box.trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-dark .trumbowyg-box.trumbowyg-box-blur .trumbowyg-editor::before { + text-shadow: 0 0 7px #ccc; } + @media screen and (min-width: 0 \0 ) { + .trumbowyg-dark .trumbowyg-box.trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-dark .trumbowyg-box.trumbowyg-box-blur .trumbowyg-editor::before { + color: rgba(20, 20, 20, 0.6) !important; } } + @supports (-ms-accelerator: true) { + .trumbowyg-dark .trumbowyg-box.trumbowyg-box-blur .trumbowyg-editor *, .trumbowyg-dark .trumbowyg-box.trumbowyg-box-blur .trumbowyg-editor::before { + color: rgba(20, 20, 20, 0.6) !important; } } + .trumbowyg-dark .trumbowyg-box svg { + fill: #ecf0f1; + color: #ecf0f1; } + +.trumbowyg-dark .trumbowyg-button-pane { + background-color: #222; + border-bottom-color: #343434; } + .trumbowyg-dark .trumbowyg-button-pane::after { + background: #343434; } + .trumbowyg-dark .trumbowyg-button-pane .trumbowyg-button-group:not(:empty)::before { + background-color: #343434; } + .trumbowyg-dark .trumbowyg-button-pane .trumbowyg-button-group:not(:empty) .trumbowyg-fullscreen-button svg { + color: transparent; } + .trumbowyg-dark .trumbowyg-button-pane.trumbowyg-disable .trumbowyg-button-group::before { + background-color: #2a2a2a; } + .trumbowyg-dark .trumbowyg-button-pane button:not(.trumbowyg-disable):hover, + .trumbowyg-dark .trumbowyg-button-pane button:not(.trumbowyg-disable):focus, + .trumbowyg-dark .trumbowyg-button-pane button.trumbowyg-active { + background-color: #333; } + .trumbowyg-dark .trumbowyg-button-pane .trumbowyg-open-dropdown::after { + border-top-color: #fff; } + +.trumbowyg-dark .trumbowyg-fullscreen .trumbowyg-button-group .trumbowyg-fullscreen-button svg { + color: #ecf0f1; + fill: transparent; } + +.trumbowyg-dark .trumbowyg-dropdown { + border-color: #222; + background: #333; + box-shadow: rgba(0, 0, 0, 0.3) 0 2px 3px; } + .trumbowyg-dark .trumbowyg-dropdown button { + background: #333; + color: #fff !important; } + .trumbowyg-dark .trumbowyg-dropdown button:hover, .trumbowyg-dark .trumbowyg-dropdown button:focus { + background: #222; } + +.trumbowyg-dark .trumbowyg-modal-box { + background-color: #222; } + .trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-title { + border-bottom: 1px solid #555; + color: #fff; + background: #3c3c3c; } + .trumbowyg-dark .trumbowyg-modal-box label { + display: block; + position: relative; + margin: 15px 12px; + height: 27px; + line-height: 27px; + overflow: hidden; } + .trumbowyg-dark .trumbowyg-modal-box label .trumbowyg-input-infos span { + color: #eee; + background-color: #2f2f2f; + border-color: #222; } + .trumbowyg-dark .trumbowyg-modal-box label .trumbowyg-input-infos span.trumbowyg-msg-error { + color: #e74c3c; } + .trumbowyg-dark .trumbowyg-modal-box label.trumbowyg-input-error input, + .trumbowyg-dark .trumbowyg-modal-box label.trumbowyg-input-error textarea { + border-color: #e74c3c; } + .trumbowyg-dark .trumbowyg-modal-box label input { + border-color: #222; + color: #eee; + background: #333; } + .trumbowyg-dark .trumbowyg-modal-box label input:hover, .trumbowyg-dark .trumbowyg-modal-box label input:focus { + border-color: #626262; } + .trumbowyg-dark .trumbowyg-modal-box label input:focus { + background-color: #2f2f2f; } + .trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit { + background: #1b7943; } + .trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:hover, .trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:focus { + background: #25a25a; } + .trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-submit:active { + background: #176437; } + .trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset { + background: #333; + color: #ccc; } + .trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:hover, .trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:focus { + background: #444; } + .trumbowyg-dark .trumbowyg-modal-box .trumbowyg-modal-button.trumbowyg-modal-reset:active { + background: #111; } + +.trumbowyg-dark .trumbowyg-overlay { + background-color: rgba(15, 15, 15, 0.6); } diff --git a/src/Header.php b/src/Header.php index f5f96538..3186ebc1 100644 --- a/src/Header.php +++ b/src/Header.php @@ -111,7 +111,8 @@ class Header * @var array $admin_js Array of all js files to be added in admin tab */ public $admin_js = [ - 'admin' => 'public/javascript/simplemappr.admin.min.js' + 'wysiwyg' => 'public/javascript/trumbowyg.min.js', + 'admin' => 'public/javascript/simplemappr.admin.min.js' ]; /** @@ -128,6 +129,13 @@ class Header 'public/stylesheets/raw/styles.css' ]; + /** + * @var array $local_css Array of all css files to be minified + */ + public $admin_css = [ + 'public/stylesheets/raw/trumbowyg.css' + ]; + /** * Flush the caches * @@ -442,6 +450,11 @@ private function _addCombinedCss() } } } + if ($this->_isAdministrator()) { + foreach ($this->admin_css as $key => $css_file) { + $this->_addCss(''); + } + } return $this; } diff --git a/views/admin.html b/views/admin.html index 2444f18a..04a9ddad 100644 --- a/views/admin.html +++ b/views/admin.html @@ -41,12 +41,12 @@- +
- +
diff --git a/views/fragments/fragment.admin.html b/views/fragments/fragment.admin.html index efc515c0..0ab251ef 100644 --- a/views/fragments/fragment.admin.html +++ b/views/fragments/fragment.admin.html @@ -17,9 +17,10 @@
-
+ +