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 = $(' +

- +

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 @@

{% trans "Citations" %}

-

+ +