diff --git a/resource/tinymce/plugins/link/plugin.js b/resource/tinymce/plugins/link/plugin.js
index 1dd4071c30..60fde68659 100644
--- a/resource/tinymce/plugins/link/plugin.js
+++ b/resource/tinymce/plugins/link/plugin.js
@@ -58,23 +58,27 @@ tinymce.PluginManager.add('link', function(editor) {
return false;
}
- function openDetachedWindow(url) {
- // Added by Zotero
- editor.execCommand('ZoteroLinkClick', false, url);
-
+ function appendClickRemove(link, evt) {
+ document.body.appendChild(link);
+ link.dispatchEvent(evt);
+ document.body.removeChild(link);
+ }
+
+ function openDetachedWindow(url) { /* Added by Zotero */ editor.execCommand("ZoteroLinkClick", false, url); return;
// Chrome and Webkit has implemented noopener and works correctly with/without popup blocker
// Firefox has it implemented noopener but when the popup blocker is activated it doesn't work
// Edge has only implemented noreferrer and it seems to remove opener as well
// Older IE versions pre IE 11 falls back to a window.open approach
- /*if (!tinymce.Env.ie || tinymce.Env.ie > 10) {
+ if (!tinymce.Env.ie || tinymce.Env.ie > 10) {
var link = document.createElement('a');
link.target = '_blank';
link.href = url;
link.rel = 'noreferrer noopener';
var evt = document.createEvent('MouseEvents');
- evt.initMouseEvent('click', true, true, window, true, 0, 0, 0, 0, false, false, false, false, 0, null);
- link.dispatchEvent(evt);
+ evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+
+ appendClickRemove(link, evt);
} else {
var win = window.open('', '_blank');
if (win) {
@@ -84,7 +88,7 @@ tinymce.PluginManager.add('link', function(editor) {
doc.write('');
doc.close();
}
- }*/
+ }
}
function gotoLink(a) {
diff --git a/resource/tinymce/plugins/paste/plugin.js b/resource/tinymce/plugins/paste/plugin.js
index db2f73e3a0..e8fcf34f05 100644
--- a/resource/tinymce/plugins/paste/plugin.js
+++ b/resource/tinymce/plugins/paste/plugin.js
@@ -80,7 +80,7 @@
target[fragments[fragments.length - 1]] = modules[id];
}
-
+
// Expose private modules for unit tests
if (exports.AMDLC_TESTS) {
privateModules = exports.privateModules || {};
@@ -1853,4 +1853,4 @@ define("tinymce/pasteplugin/Plugin", [
});
expose(["tinymce/pasteplugin/Utils"]);
-})(this);
\ No newline at end of file
+})(window);
\ No newline at end of file
diff --git a/resource/tinymce/skins/lightgray/content.min.css b/resource/tinymce/skins/lightgray/content.min.css
index 7ffcac0b65..82beedb8f4 100644
--- a/resource/tinymce/skins/lightgray/content.min.css
+++ b/resource/tinymce/skins/lightgray/content.min.css
@@ -1 +1 @@
-body{background-color:#FFFFFF;color:#000000;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px;scrollbar-3dlight-color:#F0F0EE;scrollbar-arrow-color:#676662;scrollbar-base-color:#F0F0EE;scrollbar-darkshadow-color:#DDDDDD;scrollbar-face-color:#E0E0DD;scrollbar-highlight-color:#F0F0EE;scrollbar-shadow-color:#F0F0EE;scrollbar-track-color:#F5F5F5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px}.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce-shy::after{content:'-'}hr{cursor:default}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected],th[data-mce-selected]{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2d8ac7}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #7ACAFF}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2d8ac7}.mce-resize-bar-dragging{background-color:blue;opacity:.25;filter:alpha(opacity=25);zoom:1}
\ No newline at end of file
+body{background-color:#FFFFFF;color:#000000;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px;scrollbar-3dlight-color:#F0F0EE;scrollbar-arrow-color:#676662;scrollbar-base-color:#F0F0EE;scrollbar-darkshadow-color:#DDDDDD;scrollbar-face-color:#E0E0DD;scrollbar-highlight-color:#F0F0EE;scrollbar-shadow-color:#F0F0EE;scrollbar-track-color:#F5F5F5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:14px}.mce-content-body .mce-reset{margin:0;padding:0;border:0;outline:0;vertical-align:top;background:transparent;text-decoration:none;color:black;font-family:Arial;font-size:11px;text-shadow:none;float:none;position:static;width:auto;height:auto;white-space:nowrap;cursor:inherit;line-height:normal;font-weight:normal;text-align:left;-webkit-tap-highlight-color:transparent;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;direction:ltr;max-width:none}.mce-object{border:1px dotted #3A3A3A;background:#D5D5D5 url(img/object.gif) no-repeat center}.mce-preview-object{display:inline-block;position:relative;margin:0 2px 0 2px;line-height:0;border:1px solid gray}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-preview-object .mce-shim{position:absolute;top:0;left:0;width:100%;height:100%;background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}figure.align-left{float:left}figure.align-right{float:right}figure.image.align-center{display:table;margin-left:auto;margin-right:auto}figure.image{display:inline-block;border:1px solid gray;margin:0 2px 0 1px;background:#f5f2f0}figure.image img{margin:8px 8px 0 8px}figure.image figcaption{margin:6px 8px 6px 8px;text-align:center}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#D5D5D5 url(img/anchor.gif) no-repeat center}.mce-nbsp,.mce-shy{background:#AAA}.mce-shy::after{content:'-'}hr{cursor:default}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td[data-mce-selected],th[data-mce-selected]{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333}.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus{outline:2px solid #2d8ac7}.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover{outline:2px solid #7ACAFF}.mce-content-body *[contentEditable=false][data-mce-selected]{outline:2px solid #2d8ac7}.mce-resize-bar-dragging{background-color:blue;opacity:.25;filter:alpha(opacity=25);zoom:1}
\ No newline at end of file
diff --git a/resource/tinymce/themes/modern/theme.js b/resource/tinymce/themes/modern/theme.js
index eb621466b3..15ed07c7a7 100644
--- a/resource/tinymce/themes/modern/theme.js
+++ b/resource/tinymce/themes/modern/theme.js
@@ -875,13 +875,16 @@ define('tinymce.modern.ui.Sidebar', [
define('tinymce.modern.ui.SkinLoaded', [
], function () {
var fireSkinLoaded = function (editor) {
+ var done = function () {
+ editor._skinLoaded = true;
+ editor.fire('SkinLoaded');
+ };
+
return function() {
if (editor.initialized) {
- editor.fire('SkinLoaded');
+ done();
} else {
- editor.on('init', function() {
- editor.fire('SkinLoaded');
- });
+ editor.on('init', done);
}
};
};
diff --git a/resource/tinymce/tinymce.js b/resource/tinymce/tinymce.js
index 29fcdf0ce3..1493f78b86 100644
--- a/resource/tinymce/tinymce.js
+++ b/resource/tinymce/tinymce.js
@@ -1,4 +1,4 @@
-// 4.5.1 (2016-12-07)
+// 4.5.2 (2017-01-04)
/**
* Compiled inline version. (Library mode)
@@ -9425,10 +9425,15 @@ define("tinymce/dom/ScriptLoader", [
var DOM = DOMUtils.DOM;
var each = Tools.each, grep = Tools.grep;
+ var isFunction = function (f) {
+ return typeof f === 'function';
+ };
+
function ScriptLoader() {
var QUEUED = 0,
LOADING = 1,
LOADED = 2,
+ FAILED = 3,
states = {},
queue = [],
scriptLoadedCallbacks = {},
@@ -9441,9 +9446,10 @@ define("tinymce/dom/ScriptLoader", [
*
* @method load
* @param {String} url Absolute URL to script to add.
- * @param {function} callback Optional callback function to execute ones this script gets loaded.
+ * @param {function} callback Optional success callback function when the script loaded successfully.
+ * @param {function} callback Optional failure callback function when the script failed to load.
*/
- function loadScript(url, callback) {
+ function loadScript(url, success, failure) {
var dom = DOM, elm, id;
// Execute callback when script is loaded
@@ -9454,21 +9460,25 @@ define("tinymce/dom/ScriptLoader", [
elm.onreadystatechange = elm.onload = elm = null;
}
- callback();
+ success();
}
function error() {
/*eslint no-console:0 */
- // Report the error so it's easier for people to spot loading errors
- if (typeof console !== "undefined" && console.log) {
- console.log("Failed to load: " + url);
- }
-
// We can't mark it as done if there is a load error since
// A) We don't want to produce 404 errors on the server and
// B) the onerror event won't fire on all browsers.
// done();
+
+ if (isFunction(failure)) {
+ failure();
+ } else {
+ // Report the error so it's easier for people to spot loading errors
+ if (typeof console !== "undefined" && console.log) {
+ console.log("Failed to load script: " + url);
+ }
+ }
}
id = dom.uniqueId();
@@ -9524,10 +9534,11 @@ define("tinymce/dom/ScriptLoader", [
*
* @method add
* @param {String} url Absolute URL to script to add.
- * @param {function} callback Optional callback function to execute ones this script gets loaded.
+ * @param {function} success Optional success callback function to execute when the script loades successfully.
* @param {Object} scope Optional scope to execute callback in.
+ * @param {function} failure Optional failure callback function to execute when the script failed to load.
*/
- this.add = this.load = function(url, callback, scope) {
+ this.add = this.load = function(url, success, scope, failure) {
var state = states[url];
// Add url to load queue
@@ -9536,14 +9547,15 @@ define("tinymce/dom/ScriptLoader", [
states[url] = QUEUED;
}
- if (callback) {
+ if (success) {
// Store away callback for later execution
if (!scriptLoadedCallbacks[url]) {
scriptLoadedCallbacks[url] = [];
}
scriptLoadedCallbacks[url].push({
- func: callback,
+ success: success,
+ failure: failure,
scope: scope || this
});
}
@@ -9558,11 +9570,12 @@ define("tinymce/dom/ScriptLoader", [
* Starts the loading of the queue.
*
* @method loadQueue
- * @param {function} callback Optional callback to execute when all queued items are loaded.
+ * @param {function} success Optional callback to execute when all queued items are loaded.
+ * @param {function} failure Optional callback to execute when queued items failed to load.
* @param {Object} scope Optional scope to execute the callback in.
*/
- this.loadQueue = function(callback, scope) {
- this.loadScripts(queue, callback, scope);
+ this.loadQueue = function(success, scope, failure) {
+ this.loadScripts(queue, success, scope, failure);
};
/**
@@ -9571,23 +9584,27 @@ define("tinymce/dom/ScriptLoader", [
*
* @method loadScripts
* @param {Array} scripts Array of queue items to load.
- * @param {function} callback Optional callback to execute ones all items are loaded.
+ * @param {function} callback Optional callback to execute when scripts is loaded successfully.
* @param {Object} scope Optional scope to execute callback in.
+ * @param {function} callback Optional callback to execute if scripts failed to load.
*/
- this.loadScripts = function(scripts, callback, scope) {
- var loadScripts;
+ this.loadScripts = function(scripts, success, scope, failure) {
+ var loadScripts, failures = [];
- function execScriptLoadedCallbacks(url) {
+ function execCallbacks(name, url) {
// Execute URL callback functions
each(scriptLoadedCallbacks[url], function(callback) {
- callback.func.call(callback.scope);
+ if (isFunction(callback[name])) {
+ callback[name].call(callback.scope);
+ }
});
scriptLoadedCallbacks[url] = undef;
}
queueLoadedCallbacks.push({
- func: callback,
+ success: success,
+ failure: failure,
scope: scope || this
});
@@ -9600,13 +9617,18 @@ define("tinymce/dom/ScriptLoader", [
// Load scripts that needs to be loaded
each(loadingScripts, function(url) {
// Script is already loaded then execute script callbacks directly
- if (states[url] == LOADED) {
- execScriptLoadedCallbacks(url);
+ if (states[url] === LOADED) {
+ execCallbacks('success', url);
+ return;
+ }
+
+ if (states[url] === FAILED) {
+ execCallbacks('failure', url);
return;
}
// Is script not loading then start loading it
- if (states[url] != LOADING) {
+ if (states[url] !== LOADING) {
states[url] = LOADING;
loading++;
@@ -9614,7 +9636,16 @@ define("tinymce/dom/ScriptLoader", [
states[url] = LOADED;
loading--;
- execScriptLoadedCallbacks(url);
+ execCallbacks('success', url);
+
+ // Load more scripts if they where added by the recently loaded script
+ loadScripts();
+ }, function () {
+ states[url] = FAILED;
+ loading--;
+
+ failures.push(url);
+ execCallbacks('failure', url);
// Load more scripts if they where added by the recently loaded script
loadScripts();
@@ -9625,7 +9656,15 @@ define("tinymce/dom/ScriptLoader", [
// No scripts are currently loading then execute all pending queue loaded callbacks
if (!loading) {
each(queueLoadedCallbacks, function(callback) {
- callback.func.call(callback.scope);
+ if (failures.length === 0) {
+ if (isFunction(callback.success)) {
+ callback.success.call(callback.scope);
+ }
+ } else {
+ if (isFunction(callback.failure)) {
+ callback.failure.call(callback.scope, failures);
+ }
+ }
});
queueLoadedCallbacks.length = 0;
@@ -9793,8 +9832,9 @@ define("tinymce/AddOnManager", [
* @method load
* @param {String} name Short name of the add-on that gets loaded.
* @param {String} addOnUrl URL to the add-on that will get loaded.
- * @param {function} callback Optional callback to execute ones the add-on is loaded.
+ * @param {function} success Optional success callback to execute when an add-on is loaded.
* @param {Object} scope Optional scope to execute the callback in.
+ * @param {function} failure Optional failure callback to execute when an add-on failed to load.
* @example
* // Loads a plugin from an external URL
* tinymce.PluginManager.load('myplugin', '/some/dir/someplugin/plugin.js');
@@ -9805,7 +9845,7 @@ define("tinymce/AddOnManager", [
* plugins: '-myplugin' // Don't try to load it again
* });
*/
- load: function(name, addOnUrl, callback, scope) {
+ load: function(name, addOnUrl, success, scope, failure) {
var self = this, url = addOnUrl;
function loadDependencies() {
@@ -9817,11 +9857,11 @@ define("tinymce/AddOnManager", [
self.load(newUrl.resource, newUrl, undefined, undefined);
});
- if (callback) {
+ if (success) {
if (scope) {
- callback.call(scope);
+ success.call(scope);
} else {
- callback.call(ScriptLoader);
+ success.call(ScriptLoader);
}
}
}
@@ -9843,7 +9883,7 @@ define("tinymce/AddOnManager", [
if (self.lookup[name]) {
loadDependencies();
} else {
- ScriptLoader.ScriptLoader.add(url, loadDependencies, scope);
+ ScriptLoader.ScriptLoader.add(url, loadDependencies, scope, failure);
}
}
};
@@ -18811,7 +18851,7 @@ define("tinymce/fmt/Preview", [
function selectorToHtml(selector, editor) {
- return parsedSelectorToHtml(parseSelector(selector, editor));
+ return parsedSelectorToHtml(parseSelector(selector), editor);
}
@@ -18934,9 +18974,9 @@ define("tinymce/fmt/Preview", [
items[0].name = name;
}
name = format.selector;
- previewFrag = parsedSelectorToHtml(items);
+ previewFrag = parsedSelectorToHtml(items, editor);
} else {
- previewFrag = parsedSelectorToHtml([name]);
+ previewFrag = parsedSelectorToHtml([name], editor);
}
previewElm = dom.select(name, previewFrag)[0] || previewFrag.firstChild;
@@ -21364,8 +21404,10 @@ define("tinymce/Formatter", [
textNode = findFirstTextNode(caretContainer);
}
- // Expand to word is caret is in the middle of a text node and the char before/after is a alpha numeric character
- if (text && offset > 0 && offset < text.length && /\w/.test(text.charAt(offset)) && /\w/.test(text.charAt(offset - 1))) {
+ // Expand to word if caret is in the middle of a text node and the char before/after is a alpha numeric character
+ var wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/;
+ if (text && offset > 0 && offset < text.length &&
+ wordcharRegex.test(text.charAt(offset)) && wordcharRegex.test(text.charAt(offset - 1))) {
// Get bookmark of caret position
bookmark = selection.getBookmark();
@@ -22952,6 +22994,10 @@ define("tinymce/EnterKey", [
// Insert new block before/after the parent block depending on caret location
if (CaretContainer.isCaretContainerBlock(parentBlock)) {
newBlock = CaretContainer.showCaretContainerBlock(parentBlock);
+ if (dom.isEmpty(parentBlock)) {
+ emptyBlock(parentBlock);
+ }
+ moveToCaretPosition(newBlock);
} else if (isCaretAtStartOrEndOfBlock()) {
insertNewBlockAfter();
} else if (isCaretAtStartOrEndOfBlock(true)) {
@@ -26051,7 +26097,7 @@ define("tinymce/util/Observable", [
return {
/**
* Fires the specified event by name. Consult the
- * event reference for more details on each event.
+ * event reference for more details on each event.
*
* @method fire
* @param {String} name Name of the event to fire.
@@ -26085,7 +26131,7 @@ define("tinymce/util/Observable", [
/**
* Binds an event listener to a specific event by name. Consult the
- * event reference for more details on each event.
+ * event reference for more details on each event.
*
* @method on
* @param {String} name Event name or space separated list of events to bind.
@@ -26103,7 +26149,7 @@ define("tinymce/util/Observable", [
/**
* Unbinds an event listener to a specific event by name. Consult the
- * event reference for more details on each event.
+ * event reference for more details on each event.
*
* @method off
* @param {String?} name Name of the event to unbind.
@@ -26125,7 +26171,7 @@ define("tinymce/util/Observable", [
/**
* Bind the event callback and once it fires the callback is removed. Consult the
- * event reference for more details on each event.
+ * event reference for more details on each event.
*
* @method once
* @param {String} name Name of the event to bind.
@@ -34409,8 +34455,12 @@ define("tinymce/util/Quirks", [
var rng = editor.selection.getRng();
var startCaretPos = CaretPosition.fromRangeStart(rng);
var endCaretPos = CaretPosition.fromRangeEnd(rng);
+ var prev = caretWalker.prev(startCaretPos);
+ var next = caretWalker.next(endCaretPos);
- return !editor.selection.isCollapsed() && !caretWalker.prev(startCaretPos) && !caretWalker.next(endCaretPos);
+ return !editor.selection.isCollapsed() &&
+ (!prev || prev.isAtStart()) &&
+ (!next || (next.isAtEnd() && startCaretPos.getNode() !== next.getNode()));
}
// Type over case delete and insert this won't cover typeover with a IME but at least it covers the common case
@@ -35199,11 +35249,11 @@ define("tinymce/file/Uploader", [
resolve(handlerSuccess(blobInfo, url));
};
- var failure = function() {
+ var failure = function(error) {
closeNotification();
uploadStatus.removeFailed(blobInfo.blobUri());
- resolvePending(blobInfo.blobUri(), handlerFailure(blobInfo, failure));
- resolve(handlerFailure(blobInfo, failure));
+ resolvePending(blobInfo.blobUri(), handlerFailure(blobInfo, error));
+ resolve(handlerFailure(blobInfo, error));
};
progress = function(percent) {
@@ -35401,6 +35451,10 @@ define("tinymce/file/ImageScanner", [
], function(Promise, Arr, Fun, Conversions, Env) {
var count = 0;
+ var uniqueId = function(prefix) {
+ return (prefix || 'blobid') + (count++);
+ };
+
return function(uploadStatus, blobCache) {
var cachedPromises = {};
@@ -35418,6 +35472,19 @@ define("tinymce/file/ImageScanner", [
image: img,
blobInfo: blobInfo
});
+ } else {
+ Conversions.uriToBlob(img.src).then(function (blob) {
+ Conversions.blobToDataUri(blob).then(function (dataUri) {
+ base64 = Conversions.parseDataUri(dataUri).data;
+ blobInfo = blobCache.create(uniqueId(), blob, base64);
+ blobCache.add(blobInfo);
+
+ resolve({
+ image: img,
+ blobInfo: blobInfo
+ });
+ });
+ });
}
return;
@@ -35435,9 +35502,7 @@ define("tinymce/file/ImageScanner", [
});
} else {
Conversions.uriToBlob(img.src).then(function(blob) {
- var blobInfoId = 'blobid' + (count++),
- blobInfo = blobCache.create(blobInfoId, blob, base64);
-
+ blobInfo = blobCache.create(uniqueId(), blob, base64);
blobCache.add(blobInfo);
resolve({
@@ -35688,6 +35753,78 @@ define("tinymce/file/UploadStatus", [
};
});
+// Included from: js/tinymce/classes/ErrorReporter.js
+
+/**
+ * ErrorReporter.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Various error reporting helper functions.
+ *
+ * @class tinymce.ErrorReporter
+ * @private
+ */
+define("tinymce/ErrorReporter", [
+ "tinymce/AddOnManager"
+], function (AddOnManager) {
+ var PluginManager = AddOnManager.PluginManager;
+
+ var resolvePluginName = function (targetUrl, suffix) {
+ for (var name in PluginManager.urls) {
+ var matchUrl = PluginManager.urls[name] + '/plugin' + suffix + '.js';
+ if (matchUrl === targetUrl) {
+ return name;
+ }
+ }
+
+ return null;
+ };
+
+ var pluginUrlToMessage = function (editor, url) {
+ var plugin = resolvePluginName(url, editor.suffix);
+ return plugin ?
+ 'Failed to load plugin: ' + plugin + ' from url ' + url :
+ 'Failed to load plugin url: ' + url;
+ };
+
+ var displayNotification = function (editor, message) {
+ editor.notificationManager.open({
+ type: 'error',
+ text: message
+ });
+ };
+
+ var displayError = function (editor, message) {
+ if (editor._skinLoaded) {
+ displayNotification(editor, message);
+ } else {
+ editor.on('SkinLoaded', function () {
+ displayNotification(editor, message);
+ });
+ }
+ };
+
+ var uploadError = function (editor, message) {
+ displayError(editor, 'Failed to upload image: ' + message);
+ };
+
+ var pluginLoadError = function (editor, url) {
+ displayError(editor, pluginUrlToMessage(editor, url));
+ };
+
+ return {
+ pluginLoadError: pluginLoadError,
+ uploadError: uploadError
+ };
+});
+
// Included from: js/tinymce/classes/EditorUpload.js
/**
@@ -35711,8 +35848,9 @@ define("tinymce/EditorUpload", [
"tinymce/file/Uploader",
"tinymce/file/ImageScanner",
"tinymce/file/BlobCache",
- "tinymce/file/UploadStatus"
-], function(Arr, Uploader, ImageScanner, BlobCache, UploadStatus) {
+ "tinymce/file/UploadStatus",
+ "tinymce/ErrorReporter"
+], function(Arr, Uploader, ImageScanner, BlobCache, UploadStatus, ErrorReporter) {
return function(editor) {
var blobCache = new BlobCache(), uploader, imageScanner, settings = editor.settings;
var uploadStatus = new UploadStatus();
@@ -35808,6 +35946,8 @@ define("tinymce/EditorUpload", [
if (uploadInfo.status && editor.settings.images_replace_blob_uris !== false) {
replaceImageUri(image, uploadInfo.url);
+ } else if (uploadInfo.error) {
+ ErrorReporter.uploadError(editor, uploadInfo.error);
}
return {
@@ -37822,6 +37962,7 @@ define("tinymce/SelectionOverrides", [
editor.$('*[data-mce-selected]').removeAttr('data-mce-selected');
node.setAttribute('data-mce-selected', 1);
selectedContentEditableNode = node;
+ hideFakeCaret();
return range;
}
@@ -38005,13 +38146,14 @@ define("tinymce/Editor", [
"tinymce/EditorUpload",
"tinymce/SelectionOverrides",
"tinymce/util/Uuid",
- "tinymce/ui/Sidebar"
+ "tinymce/ui/Sidebar",
+ "tinymce/ErrorReporter"
], function(
DOMUtils, DomQuery, AddOnManager, NodeChange, Node, DomSerializer, Serializer,
Selection, Formatter, UndoManager, EnterKey, ForceBlocks, EditorCommands,
URI, ScriptLoader, EventUtils, WindowManager, NotificationManager,
Schema, DomParser, Quirks, Env, Tools, Delay, EditorObservable, Mode, Shortcuts, EditorUpload,
- SelectionOverrides, Uuid, Sidebar
+ SelectionOverrides, Uuid, Sidebar, ErrorReporter
) {
// Shorten these names
var DOM = DOMUtils.DOM, ThemeManager = AddOnManager.ThemeManager, PluginManager = AddOnManager.PluginManager;
@@ -38407,6 +38549,12 @@ define("tinymce/Editor", [
});
scriptLoader.loadQueue(function() {
+ if (!self.removed) {
+ self.init();
+ }
+ }, self, function (urls) {
+ ErrorReporter.pluginLoadError(self, urls[0]);
+
if (!self.removed) {
self.init();
}
@@ -40695,7 +40843,7 @@ define("tinymce/EditorManager", [
* @property minorVersion
* @type String
*/
- minorVersion: '5.1',
+ minorVersion: '5.2',
/**
* Release date of TinyMCE build.
@@ -40703,7 +40851,7 @@ define("tinymce/EditorManager", [
* @property releaseDate
* @type String
*/
- releaseDate: '2016-12-07',
+ releaseDate: '2017-01-04',
/**
* Collection of editor instances.
@@ -45239,6 +45387,73 @@ define("tinymce/ui/FlowLayout", [
});
});
+// Included from: js/tinymce/classes/fmt/FontInfo.js
+
+/**
+ * FontInfo.js
+ *
+ * Released under LGPL License.
+ * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/**
+ * Internal class for computing font size for elements.
+ *
+ * @private
+ * @class tinymce.fmt.FontInfo
+ */
+define("tinymce/fmt/FontInfo", [
+ "tinymce/dom/DOMUtils"
+], function(DOMUtils) {
+ var getSpecifiedFontProp = function (propName, rootElm, elm) {
+ while (elm !== rootElm) {
+ if (elm.style[propName]) {
+ return elm.style[propName];
+ }
+
+ elm = elm.parentNode;
+ }
+
+ return 0;
+ };
+
+ var toPt = function (fontSize) {
+ if (/[0-9.]+px$/.test(fontSize)) {
+ return Math.round(parseInt(fontSize, 10) * 72 / 96) + 'pt';
+ }
+
+ return fontSize;
+ };
+
+ var normalizeFontFamily = function (fontFamily) {
+ // 'Font name', Font -> Font name,Font
+ return fontFamily.replace(/[\'\"]/g, '').replace(/,\s+/g, ',');
+ };
+
+ var getComputedFontProp = function (propName, elm) {
+ return DOMUtils.DOM.getStyle(elm, propName, true);
+ };
+
+ var getFontSize = function (rootElm, elm) {
+ var specifiedFontSize = getSpecifiedFontProp('fontSize', rootElm, elm);
+ return specifiedFontSize ? specifiedFontSize : getComputedFontProp('fontSize', elm);
+ };
+
+ var getFontFamily = function (rootElm, elm) {
+ var specifiedFontSize = getSpecifiedFontProp('fontFamily', rootElm, elm);
+ return normalizeFontFamily(specifiedFontSize ? specifiedFontSize : getComputedFontProp('fontFamily', elm));
+ };
+
+ return {
+ getFontSize: getFontSize,
+ getFontFamily: getFontFamily,
+ toPt: toPt
+ };
+});
+
// Included from: js/tinymce/classes/ui/FormatControls.js
/**
@@ -45265,8 +45480,9 @@ define("tinymce/ui/FormatControls", [
"tinymce/util/Arr",
"tinymce/dom/DOMUtils",
"tinymce/EditorManager",
- "tinymce/Env"
-], function(Control, Widget, FloatPanel, Tools, Arr, DOMUtils, EditorManager, Env) {
+ "tinymce/Env",
+ "tinymce/fmt/FontInfo"
+], function(Control, Widget, FloatPanel, Tools, Arr, DOMUtils, EditorManager, Env, FontInfo) {
var each = Tools.each;
var flatten = function (ar) {
@@ -45341,6 +45557,67 @@ define("tinymce/ui/FormatControls", [
};
}
+ function createFontNameListBoxChangeHandler(items) {
+ return function() {
+ var self = this;
+
+ var getFirstFont = function (fontFamily) {
+ return fontFamily ? fontFamily.split(',')[0] : '';
+ };
+
+ editor.on('nodeChange', function(e) {
+ var fontFamily, value = null;
+
+ fontFamily = FontInfo.getFontFamily(editor.getBody(), e.element);
+
+ each(items, function(item) {
+ if (item.value.toLowerCase() === fontFamily.toLowerCase()) {
+ value = item.value;
+ }
+ });
+
+ each(items, function(item) {
+ if (!value && getFirstFont(item.value).toLowerCase() === getFirstFont(fontFamily).toLowerCase()) {
+ value = item.value;
+ }
+ });
+
+ self.value(value);
+
+ if (!value && fontFamily) {
+ self.text(getFirstFont(fontFamily));
+ }
+ });
+ };
+ }
+
+ function createFontSizeListBoxChangeHandler(items) {
+ return function() {
+ var self = this;
+
+ editor.on('nodeChange', function(e) {
+ var px, pt, value = null;
+
+ px = FontInfo.getFontSize(editor.getBody(), e.element);
+ pt = FontInfo.toPt(px);
+
+ each(items, function(item) {
+ if (item.value === px) {
+ value = px;
+ } else if (item.value === pt) {
+ value = pt;
+ }
+ });
+
+ self.value(value);
+
+ if (!value) {
+ self.text(pt);
+ }
+ });
+ };
+ }
+
function createFormats(formats) {
formats = formats.replace(/;$/, '').split(';');
@@ -45724,7 +46001,7 @@ define("tinymce/ui/FormatControls", [
selectall: ['Select all', 'SelectAll', 'Meta+A'],
bold: ['Bold', 'Bold', 'Meta+B'],
italic: ['Italic', 'Italic', 'Meta+I'],
- underline: ['Underline', 'Underline'],
+ underline: ['Underline', 'Underline', 'Meta+U'],
strikethrough: ['Strikethrough', 'Strikethrough'],
subscript: ['Subscript', 'Subscript'],
superscript: ['Superscript', 'Superscript'],
@@ -45877,7 +46154,7 @@ define("tinymce/ui/FormatControls", [
tooltip: 'Font Family',
values: items,
fixedWidth: true,
- onPostRender: createListBoxChangeHandler(items, 'fontname'),
+ onPostRender: createFontNameListBoxChangeHandler(items),
onselect: function(e) {
if (e.control.settings.value) {
editor.execCommand('FontName', false, e.control.settings.value);
@@ -45907,7 +46184,7 @@ define("tinymce/ui/FormatControls", [
tooltip: 'Font Sizes',
values: items,
fixedWidth: true,
- onPostRender: createListBoxChangeHandler(items, 'fontsize'),
+ onPostRender: createFontSizeListBoxChangeHandler(items),
onclick: function(e) {
if (e.control.settings.value) {
editor.execCommand('FontSize', false, e.control.settings.value);