jsharmony-cms
Version:
737 lines (696 loc) • 24.3 kB
JavaScript
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*
* Version: 5.3.2 (2020-06-10)
*/
/* global tinymce */
(function () {
'use strict';
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
var noop = function () {
};
var constant = function (value) {
return function () {
return value;
};
};
function curry(fn) {
var initialArgs = [];
for (var _i = 1; _i < arguments.length; _i++) {
initialArgs[_i - 1] = arguments[_i];
}
return function () {
var restArgs = [];
for (var _i = 0; _i < arguments.length; _i++) {
restArgs[_i] = arguments[_i];
}
var all = initialArgs.concat(restArgs);
return fn.apply(null, all);
};
}
var never = constant(false);
var always = constant(true);
var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
var global$2 = tinymce.util.Tools.resolve('tinymce.util.XHR');
var $ = tinymce.dom.DomQuery;
var cleanupSnippetPreviewHandlers = undefined;
var getCreationDateClasses = function (editor) {
return editor.getParam('template_cdate_classes', 'cdate');
};
var getModificationDateClasses = function (editor) {
return editor.getParam('template_mdate_classes', 'mdate');
};
var getSelectedContentClasses = function (editor) {
return editor.getParam('template_selected_content_classes', 'selcontent');
};
var getPreviewReplaceValues = function (editor) {
return editor.getParam('template_preview_replace_values');
};
var getTemplateReplaceValues = function (editor) {
return editor.getParam('template_replace_values');
};
var getTemplates = function (editorSettings) {
return editorSettings.webSnippetsPath;
};
var getCdateFormat = function (editor) {
return editor.getParam('template_cdate_format', editor.translate('%Y-%m-%d'));
};
var getMdateFormat = function (editor) {
return editor.getParam('template_mdate_format', editor.translate('%Y-%m-%d'));
};
var addZeros = function (value, len) {
value = '' + value;
if (value.length < len) {
for (var i = 0; i < len - value.length; i++) {
value = '0' + value;
}
}
return value;
};
var isHtmlDocument = function(html) {
return /<\s*html(.|\r|\n)*<\s*body/.test(html);
};
var getDateTime = function (editor, fmt, date) {
var daysShort = 'Sun Mon Tue Wed Thu Fri Sat Sun'.split(' ');
var daysLong = 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday'.split(' ');
var monthsShort = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ');
var monthsLong = 'January February March April May June July August September October November December'.split(' ');
date = date || new Date();
fmt = fmt.replace('%D', '%m/%d/%Y');
fmt = fmt.replace('%r', '%I:%M:%S %p');
fmt = fmt.replace('%Y', '' + date.getFullYear());
fmt = fmt.replace('%y', '' + date.getYear());
fmt = fmt.replace('%m', addZeros(date.getMonth() + 1, 2));
fmt = fmt.replace('%d', addZeros(date.getDate(), 2));
fmt = fmt.replace('%H', '' + addZeros(date.getHours(), 2));
fmt = fmt.replace('%M', '' + addZeros(date.getMinutes(), 2));
fmt = fmt.replace('%S', '' + addZeros(date.getSeconds(), 2));
fmt = fmt.replace('%I', '' + ((date.getHours() + 11) % 12 + 1));
fmt = fmt.replace('%p', '' + (date.getHours() < 12 ? 'AM' : 'PM'));
fmt = fmt.replace('%B', '' + editor.translate(monthsLong[date.getMonth()]));
fmt = fmt.replace('%b', '' + editor.translate(monthsShort[date.getMonth()]));
fmt = fmt.replace('%A', '' + editor.translate(daysLong[date.getDay()]));
fmt = fmt.replace('%a', '' + editor.translate(daysShort[date.getDay()]));
fmt = fmt.replace('%%', '%');
return fmt;
};
var createTemplateList = function (editorSettings, callback) {
return function () {
var templateList = getTemplates(editorSettings);
if (typeof templateList === 'function') {
templateList(callback);
return;
}
if (typeof templateList === 'string') {
global$2.send({
crossDomain: true,
url: templateList,
success: function (text) {
var rslt = [];
try{
rslt = JSON.parse(text);
}
catch(ex){
/* Do nothing */
}
if(rslt && rslt._error){
var jsh = window.jsHarmony && window.jsHarmony.Instances && window.jsHarmony.Instances.length && window.jsHarmony.Instances[0];
var errmsg = 'Error loading web snippets: \r\n' + (rslt._error.Message || JSON.stringify(rslt._error));
if(jsh) jsh.XExt.Alert(errmsg);
else alert(errmsg);
return;
}
var cms = window.jsHarmonyCMSInstance;
if(cms && cms.controller && cms.controller.localWebSnippets){
for(var i=cms.controller.localWebSnippets.length-1;i>=0;i--) rslt.unshift(cms.controller.localWebSnippets[i]);
}
callback(rslt);
},
error: function(message, xhr){
var res = (xhr && xhr.responseText)||'{}';
var rslt = {};
try{
rslt = JSON.parse(res);
}
catch(ex){
/* Do nothing */
}
if(rslt && rslt._error){
var jsh = window.jsHarmony && window.jsHarmony.Instances && window.jsHarmony.Instances.length && window.jsHarmony.Instances[0];
var errmsg = rslt._error.Message || JSON.stringify(rslt._error);
if(jsh) jsh.XExt.Alert('Error loading web snippets: ' + errmsg);
else alert(errmsg);
return;
}
}
});
} else {
callback(templateList);
}
};
};
var replaceTemplateValues = function (html, templateValues) {
global$1.each(templateValues, function (v, k) {
if (typeof v === 'function') {
v = v(k);
}
html = html.replace(new RegExp('\\{\\$' + k + '\\}', 'g'), v);
});
return html;
};
var replaceVals = function (editor, e) {
var dom = editor.dom, vl = getTemplateReplaceValues(editor);
global$1.each(dom.select('*', e), function (e) {
global$1.each(vl, function (v, k) {
if (dom.hasClass(e, k)) {
if (typeof vl[k] === 'function') {
vl[k](e);
}
}
});
});
};
var hasClass = function (n, c) {
return new RegExp('\\b' + c + '\\b', 'g').test(n.className);
};
var insertTemplate = function (editor, ui, html) {
var el;
var n;
var dom = editor.dom;
var sel = editor.selection.getContent();
html = replaceTemplateValues(html, getTemplateReplaceValues(editor));
el = dom.create('div', null, html);
n = dom.select('.mceTmpl', el);
if (n && n.length > 0) {
el = dom.create('div', null);
el.appendChild(n[0].cloneNode(true));
}
global$1.each(dom.select('*', el), function (n) {
if (hasClass(n, getCreationDateClasses(editor).replace(/\s+/g, '|'))) {
n.innerHTML = getDateTime(editor, getCdateFormat(editor));
}
if (hasClass(n, getModificationDateClasses(editor).replace(/\s+/g, '|'))) {
n.innerHTML = getDateTime(editor, getMdateFormat(editor));
}
if (hasClass(n, getSelectedContentClasses(editor).replace(/\s+/g, '|'))) {
n.innerHTML = sel;
}
});
replaceVals(editor, el);
el.innerHTML+='<p></p>';
editor.execCommand('mceInsertContent', false, el.innerHTML);
editor.addVisual();
};
var register = function (editor) {
editor.addCommand('mceInsertTemplate', curry(insertTemplate, editor));
};
var setup = function (editor) {
editor.on('PreProcess', function (o) {
var dom = editor.dom, dateFormat = getMdateFormat(editor);
global$1.each(dom.select('div', o.node), function (e) {
if (dom.hasClass(e, 'mceTmpl')) {
global$1.each(dom.select('*', e), function (e) {
if (dom.hasClass(e, editor.getParam('template_mdate_classes', 'mdate').replace(/\s+/g, '|'))) {
e.innerHTML = getDateTime(editor, dateFormat);
}
});
replaceVals(editor, e);
}
});
});
};
var none = function () {
return NONE;
};
var NONE = function () {
var eq = function (o) {
return o.isNone();
};
var call = function (thunk) {
return thunk();
};
var id = function (n) {
return n;
};
var me = {
fold: function (n, _s) {
return n();
},
is: never,
isSome: never,
isNone: always,
getOr: id,
getOrThunk: call,
getOrDie: function (msg) {
throw new Error(msg || 'error: getOrDie called on none.');
},
getOrNull: constant(null),
getOrUndefined: constant(undefined),
or: id,
orThunk: call,
map: none,
each: noop,
bind: none,
exists: never,
forall: always,
filter: none,
equals: eq,
equals_: eq,
toArray: function () {
return [];
},
toString: constant('none()')
};
return me;
}();
var some = function (a) {
var constant_a = constant(a);
var self = function () {
return me;
};
var bind = function (f) {
return f(a);
};
var me = {
fold: function (n, s) {
return s(a);
},
is: function (v) {
return a === v;
},
isSome: always,
isNone: never,
getOr: constant_a,
getOrThunk: constant_a,
getOrDie: constant_a,
getOrNull: constant_a,
getOrUndefined: constant_a,
or: self,
orThunk: self,
map: function (f) {
return some(f(a));
},
each: function (f) {
f(a);
},
bind: bind,
exists: bind,
forall: bind,
filter: function (f) {
return f(a) ? me : NONE;
},
toArray: function () {
return [a];
},
toString: function () {
return 'some(' + a + ')';
},
equals: function (o) {
return o.is(a);
},
equals_: function (o, elementEq) {
return o.fold(never, function (b) {
return elementEq(a, b);
});
}
};
return me;
};
var from = function (value) {
return value === null || value === undefined ? NONE : some(value);
};
var Option = {
some: some,
none: none,
from: from
};
var map = function (xs, f) {
var len = xs.length;
var r = new Array(len);
for (var i = 0; i < len; i++) {
var x = xs[i];
r[i] = f(x, i);
}
return r;
};
var findUntil = function (xs, pred, until) {
for (var i = 0, len = xs.length; i < len; i++) {
var x = xs[i];
if (pred(x, i)) {
return Option.some(x);
} else if (until(x, i)) {
break;
}
}
return Option.none();
};
var find = function (xs, pred) {
return findUntil(xs, pred, never);
};
var global$3 = tinymce.util.Tools.resolve('tinymce.util.Promise');
var hasOwnProperty = Object.hasOwnProperty;
var get = function (obj, key) {
return has(obj, key) ? Option.from(obj[key]) : Option.none();
};
var has = function (obj, key) {
return hasOwnProperty.call(obj, key);
};
var entitiesAttr = {
'"': '"',
'<': '<',
'>': '>',
'&': '&',
'\'': '''
};
var htmlEscape = function (html) {
if(!html) return '';
return html.replace(/["'<>&]/g, function (match) {
return get(entitiesAttr, match).getOr(match);
});
};
var getPreviewContent = function (editor, html, useIframe) {
if (useIframe && !isHtmlDocument(html)) {
var contentCssLinks_1 = '';
global$1.each(editor.contentCSS, function (url) {
contentCssLinks_1 += '<link type="text/css" rel="stylesheet" href="' + editor.documentBaseURI.toAbsolute(url) + '">';
});
var bodyClass = editor.settings.body_class || '';
if (bodyClass.indexOf('=') !== -1) {
bodyClass = editor.getParam('body_class', '', 'hash');
bodyClass = bodyClass[editor.id] || '';
}
var encode = editor.dom.encode;
var directionality = editor.getBody().dir;
var dirAttr = directionality ? ' dir="' + encode(directionality) + '"' : '';
html = '<!DOCTYPE html>' + '<html>' + '<head>' + contentCssLinks_1 + '</head>' + '<body class="' + encode(bodyClass) + '"' + dirAttr + '>' + html + '</body>' + '</html>';
}
return replaceTemplateValues(html, getPreviewReplaceValues(editor));
};
var open = function (editor, templateList) {
var createTemplates = function () {
if (!templateList || templateList.length === 0) {
var message = editor.translate('No web snippets defined.'+(!templateList ? ' Set defaultEditorConfig.webSnippetsPath in the CMS site config.' : ''));
var jsh = window.jsHarmony && window.jsHarmony.Instances && window.jsHarmony.Instances.length && window.jsHarmony.Instances[0];
if(jsh) jsh.XExt.Alert(message);
else {
editor.notificationManager.open({
text: message,
type: 'info'
});
}
return Option.none();
}
return Option.from(global$1.map(templateList, function (template, index) {
var isUrlTemplate = function (t) {
return t.url !== undefined;
};
return {
selected: index === 0,
text: template.title,
value: {
url: isUrlTemplate(template) ? Option.from(template.url) : Option.none(),
content: !isUrlTemplate(template) ? Option.from(template.content) : Option.none(),
description: template.description,
remote: !!template.remote
}
};
}));
};
var createSelectBoxItems = function (templates) {
return map(templates, function (t) {
return {
text: t.text,
value: t.text
};
});
};
var findTemplate = function (templates, templateTitle) {
return find(templates, function (t) {
return t.text === templateTitle;
});
};
var loadFailedAlert = function (api, desc, err) {
var errmsg = 'Could not load the web snippet "'+desc+'"';
if(err) errmsg += ': '+err.toString();
editor.windowManager.alert(errmsg, function () {
return api.focus('template');
});
};
var getTemplateContent = function (t) {
return new global$3(function (resolve, reject) {
t.value.url.fold(function () {
return resolve(t.value.content.getOr(''));
}, function (url) {
return global$2.send({
crossDomain: true,
url: url,
success: function (html) {
resolve(html);
},
error: function (err) {
reject('Error downloading template');
}
});
});
});
};
var onChange = function (templates, updateDialog) {
return function (api, change) {
detachSnippetPreview();
if (change.name === 'template') {
var newTemplateTitle = api.getData().template;
findTemplate(templates, newTemplateTitle).each(function (t) {
api.block('Loading...');
getTemplateContent(t).then(function (previewHtml) {
updateDialog(api, t, previewHtml);
}).catch(function (err) {
updateDialog(api, t, '');
api.disable('save');
loadFailedAlert(api, newTemplateTitle, err);
});
});
}
};
};
var onSubmit = function (templates) {
return function (api) {
detachSnippetPreview();
var data = api.getData();
findTemplate(templates, data.template).each(function (t) {
getTemplateContent(t).then(function (previewHtml) {
insertTemplate(editor, false, (previewHtml||'').toString().trim());
api.close();
}).catch(function (err) {
api.disable('save');
loadFailedAlert(api, data.template, err);
});
});
};
};
var attachSnippetPreview = function(snippetContent) {
detachSnippetPreview();
var $wrapper = $('<div id="jsharmony_cms_snippetPreviewWrapper"></div>');
$wrapper.append(snippetContent);
$wrapper
.css('position', 'fixed')
.css('z-index', '999999999')
.css('width', '1px')
.css('height', '1px')
.css('overflow', 'auto');
$('body').append($wrapper);
$(window).on('resize', positionSnippetPreview);
cleanupSnippetPreviewHandlers = function() {
$(window).off('resize', positionSnippetPreview);
cleanupSnippetPreviewHandlers = undefined;
};
};
var detachSnippetPreview = function() {
if (cleanupSnippetPreviewHandlers) cleanupSnippetPreviewHandlers();
$('#jsharmony_cms_snippetPreviewWrapper').remove();
};
var positionSnippetPreview = function() {
var $snippetWrapper = $('#jsharmony_cms_snippetPreviewWrapper');
var $anchor = $('#jsharmony_cms_snippetPreviewAnchor');
var $formWrapper = $anchor.closest('.tox-form');
if ($snippetWrapper.length < 1 || $anchor.length < 1) return;
function getMaxZIndex(obj){
if(!obj) return 0;
var parents = [];
var parentObj = obj;
var parentNodeName = (parentObj.nodeName||'').toUpperCase();
while(parentObj && (parentNodeName != 'HTML') && (parentNodeName != 'BODY')){
parents.unshift(parentObj);
parentObj = parentObj.parentNode;
if(parentObj) parentNodeName = (parentObj.nodeName||'').toUpperCase();
}
for(var i=0;i<parents.length;i++){
var zIndex = stackZIndex(parents[i]);
if(zIndex>=0) return zIndex;
}
return 0;
}
function stackZIndex(obj){
if(!obj) return false;
var nodeName = (obj.nodeName||'').toUpperCase();
if(nodeName=='HTML') return 0;
var objStyle = window.getComputedStyle(obj);
if(!objStyle) return -1;
var zIndex = parseInt(objStyle.zIndex);
var hasZIndex = !isNaN(zIndex);
var objPosition = (objStyle.position||'').toLowerCase();
if(hasZIndex){
if((objPosition=='absolute')||(objPosition=='relative')) return zIndex||0;
}
if((objPosition=='fixed')||(objPosition=='sticky')) return zIndex||0;
return -1;
}
var zIndex = getMaxZIndex($anchor[0]);
if(zIndex < 2147483647) zIndex++;
var anchorRect = $anchor[0].getBoundingClientRect();
var formRect = $formWrapper[0].getBoundingClientRect();
var x = anchorRect.left;
var y = anchorRect.top;
var width = anchorRect.width;
var height = formRect.top + formRect.height - y;
$snippetWrapper.css({
width: width + 'px',
height: height + 'px',
top: y + 'px',
left: x + 'px',
zIndex: zIndex,
});
};
var openDialog = function (templates) {
var selectBoxItems = createSelectBoxItems(templates);
var buildDialogSpec = function (bodyItems, initialData) {
return {
title: 'Insert Web Snippet',
size: 'large',
body: {
type: 'panel',
items: bodyItems
},
initialData: initialData,
buttons: [
{
type: 'cancel',
name: 'cancel',
text: 'Cancel'
},
{
type: 'submit',
name: 'save',
text: 'Insert',
primary: true
}
],
onCancel: function() { detachSnippetPreview(); },
onSubmit: onSubmit(templates),
onChange: onChange(templates, updateDialog)
};
};
var updateDialog = function (dialogApi, template, previewHtml) {
var initialData = {
template: template.text
};
var isIframeSnippet = isHtmlDocument(previewHtml);
var content = getPreviewContent(editor, previewHtml, isIframeSnippet);
var bodyItems = [
{
type: 'selectbox',
name: 'template',
label: 'Web Snippets',
items: selectBoxItems
},
{
type: 'htmlpanel',
html: '<p aria-live="polite">' + htmlEscape(template.value.description) + '</p>'
}
];
if (isIframeSnippet) {
if(template.value && template.value.remote){
initialData.preview = '';
bodyItems.push({
type: 'htmlpanel',
html: '<div id="jsharmony_cms_snippetPreviewPlaceholder"></div>'
});
}
else {
initialData.preview = content;
}
bodyItems.push({
label: 'Preview',
type: 'iframe',
name: 'preview',
sandboxed: false
});
} else {
bodyItems.push({
type: 'label',
label: 'Preview',
items: [{
label: 'Preview',
type: 'htmlpanel',
html: '<div id="jsharmony_cms_snippetPreviewAnchor"></div>'
}]
});
}
dialogApi.unblock();
dialogApi.redial(buildDialogSpec(bodyItems, initialData));
dialogApi.focus('template');
if(isIframeSnippet && template.value && template.value.remote){
var $placeholder = $('#jsharmony_cms_snippetPreviewPlaceholder');
var $iframe = $placeholder.closest('.tox-form').find('iframe');
$iframe.prop('src', template.value.url.getOr(''));
}
else if (!isIframeSnippet && (previewHtml||'').toString().trim()) {
attachSnippetPreview(content);
positionSnippetPreview();
}
};
var dialogApi = editor.windowManager.open(buildDialogSpec([], {
template: '',
preview: ''
}));
dialogApi.block('Loading...');
getTemplateContent(templates[0]).then(function (previewHtml) {
updateDialog(dialogApi, templates[0], previewHtml);
}).catch(function (err) {
updateDialog(dialogApi, templates[0], '');
dialogApi.disable('save');
loadFailedAlert(dialogApi, templates[0].value.url.getOr(''), err);
});
};
var optTemplates = createTemplates();
optTemplates.each(openDialog);
};
var showDialog = function (editor) {
return function (templates) {
open(editor, templates);
};
};
var register$1 = function (editor) {
editor.ui.registry.addButton('jsHarmonyCmsWebSnippet', {
icon: 'template',
text: 'Web Snippet',
tooltip: 'Web Snippet',
onAction: createTemplateList(editor.settings, showDialog(editor))
});
editor.ui.registry.addMenuItem('jsHarmonyCmsWebSnippet', {
icon: 'template',
text: 'Web Snippet...',
onAction: createTemplateList(editor.settings, showDialog(editor))
});
};
function Plugin () {
global.add('jsHarmonyCmsWebSnippet', function (editor) {
register$1(editor);
register(editor);
setup(editor);
});
}
Plugin();
}());