732 lines
26 KiB
JavaScript
732 lines
26 KiB
JavaScript
/**
|
|
* Front-submit TinyMCE tools matching the reference article editor.
|
|
*
|
|
* @package AKSRT
|
|
*/
|
|
(function (window, document) {
|
|
'use strict';
|
|
|
|
if (!window.tinymce || !window.tinymce.PluginManager) {
|
|
return;
|
|
}
|
|
|
|
var cfg = window.aksrtSubmitData || {};
|
|
var editorCfg = cfg.editor || {};
|
|
var i18n = cfg.i18n || {};
|
|
var activeModal = null;
|
|
|
|
function notify(message, type, duration, id) {
|
|
if (typeof window.notyf === 'function') {
|
|
window.notyf(
|
|
message,
|
|
type,
|
|
duration === undefined ? 5 : duration,
|
|
id || 'aksrt-front-submit-editor-media-toast'
|
|
);
|
|
}
|
|
}
|
|
|
|
function escapeAttr(value) {
|
|
return String(value)
|
|
.replace(/&/g, '&')
|
|
.replace(/"/g, '"')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>');
|
|
}
|
|
|
|
function validHttpUrl(value) {
|
|
var raw = String(value).trim();
|
|
if (!/^https?:\/\//i.test(raw)) {
|
|
return '';
|
|
}
|
|
try {
|
|
var url = new URL(raw);
|
|
return url.protocol === 'http:' || url.protocol === 'https:' ? url.href : '';
|
|
} catch (error) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
function imageMarkup(url, attachmentId, alt) {
|
|
var safeUrl = validHttpUrl(url);
|
|
if (!safeUrl) {
|
|
return '';
|
|
}
|
|
var idAttr = attachmentId ? ' data-edit-file-id="' + Number(attachmentId) + '"' : '';
|
|
var altAttr = alt ? ' alt="' + escapeAttr(alt) + '"' : ' alt=""';
|
|
return '<p><img src="' + escapeAttr(safeUrl) + '"' + idAttr + altAttr + '></p>';
|
|
}
|
|
|
|
function videoMarkup(url, attachmentId, name) {
|
|
var safeUrl = validHttpUrl(url);
|
|
if (!safeUrl) {
|
|
return '';
|
|
}
|
|
var idAttr = attachmentId ? ' data-edit-file-id="' + Number(attachmentId) + '"' : '';
|
|
return '<div contenteditable="false" data-video-url="' + escapeAttr(safeUrl) +
|
|
'" data-video-name="' + escapeAttr(name || safeUrl) + '"' + idAttr +
|
|
' class="new-dplayer post-dplayer dplayer"></div>';
|
|
}
|
|
|
|
function fileMarkup(url, attachmentId, name) {
|
|
var safeUrl = validHttpUrl(url);
|
|
if (!safeUrl) {
|
|
return '';
|
|
}
|
|
var filename = String(name || safeUrl.split('/').pop() || i18n.attachment || '附件');
|
|
var idAttr = attachmentId ? ' data-download-file="' + Number(attachmentId) + '"' : '';
|
|
return '<div class="mb20 muted-box file-download-box" contenteditable="false">' +
|
|
'<div class="flex ac jsb"><div class="flex ac"><div class="mr10">' +
|
|
'<div class="file-download-icon"><i class="fa fas fa-file-alt" aria-hidden="true"></i></div></div>' +
|
|
'<div class="text-ellipsis-2 file-download-name" contenteditable="true">' + escapeAttr(filename) + '</div>' +
|
|
'</div><div class="flex0 ml20"><a href="' + escapeAttr(safeUrl) + '" data-mce-href="' +
|
|
escapeAttr(safeUrl) + '"' + idAttr + ' class="but c-blue file-download-btn">' +
|
|
'<i class="fa fas fa-download" aria-hidden="true"></i>' + escapeAttr(i18n.download || '下载') +
|
|
'</a></div></div></div>';
|
|
}
|
|
|
|
function embedVideoMarkup(value) {
|
|
var holder = document.createElement('div');
|
|
holder.innerHTML = String(value).trim();
|
|
var iframe = holder.querySelector('iframe');
|
|
var safeUrl = validHttpUrl(iframe ? iframe.getAttribute('src') : value);
|
|
if (!safeUrl) {
|
|
return '';
|
|
}
|
|
return '<div contenteditable="false" class="wp-block-embed is-type-video mb20">' +
|
|
'<div class="iframe-absbox" style="padding-bottom:56%;"><iframe src="' + escapeAttr(safeUrl) +
|
|
'" allowfullscreen="allowfullscreen" framespacing="0" border="0" width="100%" frameborder="no"></iframe>' +
|
|
'</div></div>';
|
|
}
|
|
|
|
function closeMediaModal() {
|
|
if (!activeModal) {
|
|
return;
|
|
}
|
|
document.removeEventListener('keydown', activeModal.onKeydown);
|
|
activeModal.root.remove();
|
|
activeModal = null;
|
|
document.body.classList.remove('aksrt-editor-media-open');
|
|
}
|
|
|
|
function acceptsFile(file, type) {
|
|
if (!file) {
|
|
return false;
|
|
}
|
|
if (type === 'image') {
|
|
return /^image\//.test(file.type || '');
|
|
}
|
|
if (type === 'video') {
|
|
return /^video\//.test(file.type || '');
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function uploadMedia(file, type) {
|
|
var uploadKey = type === 'file' ? 'resource' : type;
|
|
var upload = (cfg.uploads || {})[uploadKey] || null;
|
|
if (!upload || !upload.url) {
|
|
return Promise.reject(new Error(i18n.uploadUnavailable || '当前账号不能上传此类文件'));
|
|
}
|
|
if (!acceptsFile(file, type)) {
|
|
return Promise.reject(new Error(i18n.invalidFile || '请选择有效文件'));
|
|
}
|
|
if (upload.maxSize && file.size > upload.maxSize) {
|
|
return Promise.reject(new Error(i18n.fileTooLarge || '文件大小超过限制'));
|
|
}
|
|
|
|
var body = new FormData();
|
|
body.append('file', file);
|
|
return fetch(upload.url, {
|
|
method: 'POST',
|
|
credentials: 'same-origin',
|
|
headers: { 'X-WP-Nonce': cfg.restNonce || '' },
|
|
body: body,
|
|
}).then(function (response) {
|
|
return response.json().catch(function () {
|
|
return {};
|
|
}).then(function (payload) {
|
|
if (!response.ok || !payload || !payload.success || !payload.url) {
|
|
throw new Error((payload && payload.message) || i18n.error || '文件上传失败');
|
|
}
|
|
return payload;
|
|
});
|
|
});
|
|
}
|
|
|
|
function mediaDefinition(type) {
|
|
if (type === 'video') {
|
|
return {
|
|
title: i18n.insertVideo || '插入视频',
|
|
uploadTab: i18n.uploadVideo || '上传视频',
|
|
externalTab: i18n.externalVideo || '外链视频',
|
|
embedTab: i18n.embedVideo || '嵌入视频',
|
|
accept: 'video/*',
|
|
multiple: false,
|
|
canUpload: !!editorCfg.canUploadVideo && !!((cfg.uploads || {}).video),
|
|
canEmbed: !!editorCfg.canEmbedVideo,
|
|
select: i18n.selectVideo || '选择或拖入视频',
|
|
hint: i18n.videoUploadHint || '上传完成后自动插入正文',
|
|
externalHint: i18n.externalVideoHint || '请填写视频文件地址:',
|
|
};
|
|
}
|
|
if (type === 'file') {
|
|
return {
|
|
title: i18n.insertFile || '上传附件',
|
|
uploadTab: i18n.uploadFile || '上传附件',
|
|
externalTab: i18n.externalFile || '输入地址',
|
|
accept: '*/*',
|
|
multiple: false,
|
|
canUpload: !!editorCfg.canUploadFile && !!((cfg.uploads || {}).resource),
|
|
canEmbed: false,
|
|
select: i18n.selectFile || '选择或拖入附件',
|
|
hint: i18n.fileUploadHint || '上传完成后自动插入正文',
|
|
externalHint: i18n.externalFileHint || '请填写附件地址:',
|
|
};
|
|
}
|
|
return {
|
|
title: i18n.insertImage || '插入图片',
|
|
uploadTab: i18n.uploadImage || '上传图片',
|
|
externalTab: i18n.externalImage || '外链图片',
|
|
accept: 'image/gif,image/jpeg,image/png,image/webp',
|
|
multiple: true,
|
|
canUpload: !!editorCfg.canUploadImage && !!((cfg.uploads || {}).image),
|
|
canEmbed: false,
|
|
select: i18n.selectImages || '选择或拖入图片',
|
|
hint: i18n.imageUploadHint || '可批量选择,上传完成后自动插入正文',
|
|
externalHint: i18n.externalImageHint || '每行填写一个图片地址:',
|
|
};
|
|
}
|
|
|
|
function mediaMarkup(type, item) {
|
|
if (type === 'video') {
|
|
return videoMarkup(item.url, item.attachment_id, item.filename || item.name || '');
|
|
}
|
|
if (type === 'file') {
|
|
return fileMarkup(item.url, item.attachment_id, item.filename || item.name || '');
|
|
}
|
|
return imageMarkup(item.url, item.attachment_id, item.name || '');
|
|
}
|
|
|
|
function createMediaModal(editor, type) {
|
|
closeMediaModal();
|
|
|
|
var definition = mediaDefinition(type);
|
|
var canUpload = definition.canUpload;
|
|
var firstTab = canUpload ? 'upload' : 'external';
|
|
var root = document.createElement('div');
|
|
root.className = 'aksrt-editor-media';
|
|
root.setAttribute('data-editor-media-type', type);
|
|
root.setAttribute('role', 'dialog');
|
|
root.setAttribute('aria-modal', 'true');
|
|
root.setAttribute('aria-labelledby', 'aksrt-editor-media-title');
|
|
root.innerHTML =
|
|
'<button type="button" class="aksrt-editor-media__backdrop" data-editor-media-close tabindex="-1" aria-label="' +
|
|
escapeAttr(i18n.close || '关闭') + '"></button>' +
|
|
'<div class="aksrt-editor-media__dialog" tabindex="-1">' +
|
|
'<button type="button" class="aksrt-editor-media__close" data-editor-media-close aria-label="' +
|
|
escapeAttr(i18n.close || '关闭') + '">×</button>' +
|
|
'<h3 id="aksrt-editor-media-title" class="aksrt-editor-media__title">' +
|
|
escapeAttr(definition.title) + '</h3>' +
|
|
'<div class="aksrt-editor-media__tabs" role="tablist">' +
|
|
(canUpload
|
|
? '<button type="button" class="is-active" role="tab" aria-selected="true" data-editor-media-tab="upload">' +
|
|
escapeAttr(definition.uploadTab) + '</button>'
|
|
: '') +
|
|
'<button type="button" class="' + (firstTab === 'external' ? 'is-active' : '') + '" role="tab" aria-selected="' +
|
|
(canUpload ? 'false' : 'true') + '" data-editor-media-tab="external">' +
|
|
escapeAttr(definition.externalTab) + '</button>' +
|
|
(definition.canEmbed
|
|
? '<button type="button" role="tab" aria-selected="false" data-editor-media-tab="embed">' +
|
|
escapeAttr(definition.embedTab) + '</button>'
|
|
: '') +
|
|
'</div>' +
|
|
'<div class="aksrt-editor-media__panels">' +
|
|
(canUpload
|
|
? '<section class="aksrt-editor-media__panel is-active" data-editor-media-panel="upload">' +
|
|
'<label class="aksrt-editor-media__drop">' +
|
|
'<input type="file" accept="' + escapeAttr(definition.accept) + '"' +
|
|
(definition.multiple ? ' multiple' : '') + ' data-editor-media-files>' +
|
|
'<i class="fa fas fa-cloud-upload-alt" aria-hidden="true"></i>' +
|
|
'<strong>' + escapeAttr(definition.select) + '</strong>' +
|
|
'<span>' + escapeAttr(definition.hint) + '</span>' +
|
|
'</label>' +
|
|
'<div class="aksrt-editor-media__selection" data-editor-media-selection></div>' +
|
|
'<button type="button" class="but c-blue aksrt-editor-media__submit" data-editor-media-upload disabled>' +
|
|
escapeAttr(i18n.confirmUpload || '确认上传') + '</button>' +
|
|
'</section>'
|
|
: '') +
|
|
'<section class="aksrt-editor-media__panel ' + (firstTab === 'external' ? 'is-active' : '') + '" data-editor-media-panel="external">' +
|
|
'<p>' + escapeAttr(definition.externalHint) + '</p>' +
|
|
'<textarea class="form-control" rows="5" placeholder="https://..." data-editor-media-urls></textarea>' +
|
|
'<button type="button" class="but c-blue aksrt-editor-media__submit" data-editor-media-external>' +
|
|
escapeAttr(i18n.confirmInsert || '确认插入') + '</button>' +
|
|
'</section>' +
|
|
(definition.canEmbed
|
|
? '<section class="aksrt-editor-media__panel" data-editor-media-panel="embed">' +
|
|
'<p>' + escapeAttr(i18n.embedVideoHint || '请输入嵌入地址或者直接粘贴 iframe 嵌入代码:') + '</p>' +
|
|
'<textarea class="form-control" rows="5" placeholder="<iframe src="https://..."></iframe>" data-editor-media-embed></textarea>' +
|
|
'<button type="button" class="but c-blue aksrt-editor-media__submit" data-editor-media-embed-submit>' +
|
|
escapeAttr(i18n.confirmEmbed || '确认嵌入') + '</button>' +
|
|
'</section>'
|
|
: '') +
|
|
'</div>' +
|
|
'</div>';
|
|
|
|
document.body.appendChild(root);
|
|
document.body.classList.add('aksrt-editor-media-open');
|
|
|
|
var fileInput = root.querySelector('[data-editor-media-files]');
|
|
var uploadButton = root.querySelector('[data-editor-media-upload]');
|
|
var selection = root.querySelector('[data-editor-media-selection]');
|
|
var drop = root.querySelector('.aksrt-editor-media__drop');
|
|
var files = [];
|
|
|
|
function showSelection() {
|
|
if (!selection || !uploadButton) {
|
|
return;
|
|
}
|
|
selection.textContent = files.length
|
|
? (definition.multiple
|
|
? (i18n.selectedFiles || '已选择 %d 个文件').replace('%d', String(files.length))
|
|
: files[0].name)
|
|
: '';
|
|
uploadButton.disabled = files.length === 0;
|
|
}
|
|
|
|
function setFiles(nextFiles) {
|
|
var candidates = Array.prototype.slice.call(nextFiles || []);
|
|
files = candidates.filter(function (file) {
|
|
return acceptsFile(file, type);
|
|
});
|
|
if (candidates.length && !files.length) {
|
|
notify(i18n.invalidFile || '请选择有效文件', 'warning');
|
|
}
|
|
if (!definition.multiple && files.length > 1) {
|
|
files = files.slice(0, 1);
|
|
}
|
|
showSelection();
|
|
}
|
|
|
|
root.addEventListener('click', function (event) {
|
|
var close = event.target.closest('[data-editor-media-close]');
|
|
if (close) {
|
|
event.preventDefault();
|
|
closeMediaModal();
|
|
return;
|
|
}
|
|
|
|
var tab = event.target.closest('[data-editor-media-tab]');
|
|
if (tab) {
|
|
var name = tab.getAttribute('data-editor-media-tab');
|
|
root.querySelectorAll('[data-editor-media-tab]').forEach(function (item) {
|
|
var active = item === tab;
|
|
item.classList.toggle('is-active', active);
|
|
item.setAttribute('aria-selected', active ? 'true' : 'false');
|
|
});
|
|
root.querySelectorAll('[data-editor-media-panel]').forEach(function (panel) {
|
|
panel.classList.toggle('is-active', panel.getAttribute('data-editor-media-panel') === name);
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (event.target.closest('[data-editor-media-external]')) {
|
|
var textarea = root.querySelector('[data-editor-media-urls]');
|
|
var urls = String(textarea ? textarea.value : '').split(/\r?\n/);
|
|
if (!definition.multiple) {
|
|
urls = urls.slice(0, 1);
|
|
}
|
|
var html = urls.map(function (url) {
|
|
return mediaMarkup(type, { url: url });
|
|
}).join('');
|
|
if (!html) {
|
|
notify(i18n.invalidMediaUrl || '请填写有效地址', 'warning');
|
|
return;
|
|
}
|
|
editor.insertContent(html + '<p></p>');
|
|
editor.nodeChanged();
|
|
closeMediaModal();
|
|
return;
|
|
}
|
|
|
|
if (event.target.closest('[data-editor-media-embed-submit]')) {
|
|
var embedInput = root.querySelector('[data-editor-media-embed]');
|
|
var embedHtml = embedVideoMarkup(embedInput ? embedInput.value : '');
|
|
if (!embedHtml) {
|
|
notify(i18n.invalidVideoUrl || '请填写有效的视频嵌入地址', 'warning');
|
|
return;
|
|
}
|
|
editor.insertContent(embedHtml + '<p></p>');
|
|
editor.nodeChanged();
|
|
closeMediaModal();
|
|
return;
|
|
}
|
|
|
|
if (event.target.closest('[data-editor-media-upload]')) {
|
|
if (!files.length || !uploadButton) {
|
|
return;
|
|
}
|
|
uploadButton.disabled = true;
|
|
uploadButton.textContent = i18n.uploading || '正在上传…';
|
|
notify(i18n.uploading || '正在上传…', 'load', '');
|
|
Promise.all(files.map(function (file) {
|
|
return uploadMedia(file, type);
|
|
})).then(function (items) {
|
|
var html = items.map(function (item) {
|
|
return mediaMarkup(type, item);
|
|
}).join('');
|
|
if (!html) {
|
|
throw new Error(i18n.error || '文件上传失败');
|
|
}
|
|
editor.insertContent(html + '<p></p>');
|
|
editor.nodeChanged();
|
|
notify(i18n.uploaded || '上传成功', 'success');
|
|
closeMediaModal();
|
|
}).catch(function (error) {
|
|
notify(error.message || i18n.error || '文件上传失败', 'danger');
|
|
uploadButton.disabled = false;
|
|
uploadButton.textContent = i18n.confirmUpload || '确认上传';
|
|
});
|
|
}
|
|
});
|
|
|
|
if (fileInput) {
|
|
fileInput.addEventListener('change', function () {
|
|
setFiles(fileInput.files);
|
|
});
|
|
}
|
|
|
|
if (drop) {
|
|
['dragenter', 'dragover'].forEach(function (name) {
|
|
drop.addEventListener(name, function (event) {
|
|
event.preventDefault();
|
|
drop.classList.add('is-dragging');
|
|
});
|
|
});
|
|
['dragleave', 'drop'].forEach(function (name) {
|
|
drop.addEventListener(name, function (event) {
|
|
event.preventDefault();
|
|
drop.classList.remove('is-dragging');
|
|
});
|
|
});
|
|
drop.addEventListener('drop', function (event) {
|
|
setFiles(event.dataTransfer && event.dataTransfer.files);
|
|
});
|
|
}
|
|
|
|
var onKeydown = function (event) {
|
|
if (event.key === 'Escape') {
|
|
closeMediaModal();
|
|
}
|
|
};
|
|
activeModal = { root: root, onKeydown: onKeydown };
|
|
document.addEventListener('keydown', onKeydown);
|
|
var focusTarget = root.querySelector('.aksrt-editor-media__dialog');
|
|
if (focusTarget) {
|
|
focusTarget.focus({ preventScroll: true });
|
|
}
|
|
}
|
|
|
|
function selectedContent(editor) {
|
|
var content = String(editor.selection.getContent() || '').trim();
|
|
return content ? '<p>' + content + '</p>' : '<p>' + escapeAttr(i18n.hiddenPlaceholder || '隐藏内容') + '</p>';
|
|
}
|
|
|
|
function insertHiddenContent(editor, item) {
|
|
var node = editor.selection.getNode();
|
|
var content = selectedContent(editor);
|
|
var suffix = '<p></p>';
|
|
if (node && editor.dom.hasClass(node, 'tinymce-hide')) {
|
|
var editable = node.querySelector('[contenteditable="true"]');
|
|
content = editable ? editable.innerHTML : content;
|
|
editor.dom.remove(node);
|
|
suffix = '';
|
|
}
|
|
|
|
editor.insertContent(
|
|
'<div class="tinymce-hide" data-aksrt-hide-type="' + escapeAttr(item.type) + '" contenteditable="false">' +
|
|
'<p class="hide-before">' + escapeAttr(item.open) + '</p>' +
|
|
'<div contenteditable="true">' + content + '</div>' +
|
|
'<p class="hide-after">' + escapeAttr(item.close) + '</p>' +
|
|
'</div>' + suffix
|
|
);
|
|
editor.nodeChanged();
|
|
}
|
|
|
|
function insertQuote(editor, colorClass) {
|
|
var node = editor.selection.getNode();
|
|
var quote = editor.dom.getParent(node, '.quote_q');
|
|
if (quote) {
|
|
quote.className = 'quote_q quote-mce' + (colorClass ? ' ' + colorClass : '');
|
|
editor.nodeChanged();
|
|
return;
|
|
}
|
|
|
|
var content = String(editor.selection.getContent() || '').trim();
|
|
if (node && node.nodeName === 'P' && node.parentNode === editor.getBody()) {
|
|
content = node.outerHTML;
|
|
editor.dom.remove(node);
|
|
} else {
|
|
content = content ? '<p>' + content + '</p>' : '<p></p>';
|
|
}
|
|
editor.insertContent(
|
|
'<div class="quote_q quote-mce' + (colorClass ? ' ' + colorClass : '') +
|
|
'" contenteditable="false"><div contenteditable="true">' + content + '</div></div><p></p>'
|
|
);
|
|
editor.nodeChanged();
|
|
}
|
|
|
|
var codeLanguages = [
|
|
['yaml', 'yaml'],
|
|
['xml/html', 'xml'],
|
|
['visualbasic', 'visualbasic'],
|
|
['vhdl', 'vhdl'],
|
|
['typescript', 'typescript'],
|
|
['swift', 'swift'],
|
|
['sql', 'sql'],
|
|
['shell', 'shell'],
|
|
['scss/sass', 'scss'],
|
|
['rust', 'rust'],
|
|
['ruby', 'ruby'],
|
|
['python', 'python'],
|
|
['powershell', 'powershell'],
|
|
['php', 'php'],
|
|
['markdown', 'markdown'],
|
|
['lua', 'lua'],
|
|
['less', 'less'],
|
|
['kotlin', 'kotlin'],
|
|
['json', 'json'],
|
|
['javascript', 'javascript'],
|
|
['java', 'java'],
|
|
['ini/conf', 'ini'],
|
|
['go/golang', 'go'],
|
|
['docker', 'dockerfile'],
|
|
['diff', 'diff'],
|
|
['css', 'css'],
|
|
['csharp', 'csharp'],
|
|
['Cpp/C++/C', 'cpp'],
|
|
['assembly', 'assembly'],
|
|
[i18n.codeGeneric || '通用高亮', 'generic'],
|
|
];
|
|
|
|
var codeThemes = [
|
|
['enlighter', 'enlighter'],
|
|
['classic', 'classic'],
|
|
['beyond', 'beyond'],
|
|
['mowtwo', 'mowtwo'],
|
|
['eclipse', 'eclipse'],
|
|
['droide', 'droide'],
|
|
['minimal', 'minimal'],
|
|
['atomic', 'atomic'],
|
|
['dracula', 'dracula'],
|
|
['bootstrap4', 'bootstrap4'],
|
|
['rowhammer', 'rowhammer'],
|
|
['godzilla', 'godzilla'],
|
|
[i18n.codeFollowGlobal || '跟随全局设置', 'qj'],
|
|
];
|
|
|
|
function listboxValues(items) {
|
|
return items.map(function (item) {
|
|
return { text: item[0], value: item[1] };
|
|
});
|
|
}
|
|
|
|
function bindCharacterCount(editor) {
|
|
var counter = null;
|
|
|
|
function getCounter() {
|
|
var container = editor.getContainer();
|
|
var statusbar = container && container.querySelector('.mce-statusbar .mce-container-body');
|
|
if (!statusbar) {
|
|
return null;
|
|
}
|
|
|
|
counter = counter || statusbar.querySelector('[data-submit-word-count]');
|
|
if (!counter) {
|
|
counter = document.createElement('span');
|
|
counter.className = 'mce-wordcount aksrt-submit-word-count';
|
|
counter.setAttribute('data-submit-word-count', '');
|
|
counter.setAttribute('aria-live', 'polite');
|
|
statusbar.appendChild(counter);
|
|
}
|
|
return counter;
|
|
}
|
|
|
|
function updateCount() {
|
|
var count = String((editor.getBody() && editor.getBody().textContent) || '')
|
|
.replace(/\s+/g, '').length;
|
|
var element = getCounter();
|
|
if (element) {
|
|
element.textContent = '字数:' + count;
|
|
}
|
|
}
|
|
|
|
editor.on('init SetContent input keyup change Undo Redo', updateCount);
|
|
}
|
|
|
|
function openCodeModal(editor) {
|
|
var selected = editor.dom.getParent(editor.selection.getNode(), 'pre.enlighter-pre');
|
|
var code = selected ? selected.querySelector('code') : null;
|
|
var width = window.innerWidth > 800 ? Math.round(window.innerWidth * 0.5) :
|
|
(window.innerWidth > 640 ? Math.round(window.innerWidth * 0.7) : window.innerWidth - 20);
|
|
var height = Math.round(window.innerHeight * 0.6);
|
|
|
|
editor.windowManager.open({
|
|
title: (selected ? (i18n.edit || '编辑') : (i18n.insert || '插入')) +
|
|
(i18n.highlightCode || '高亮代码'),
|
|
width: width,
|
|
height: height,
|
|
body: [
|
|
{
|
|
type: 'listbox',
|
|
name: 'language',
|
|
label: i18n.selectLanguage || '选择语言',
|
|
value: code ? (code.getAttribute('data-enlighter-language') || 'generic') : 'generic',
|
|
values: listboxValues(codeLanguages),
|
|
},
|
|
{
|
|
type: 'listbox',
|
|
name: 'theme',
|
|
label: i18n.codeTheme || '主题',
|
|
value: code ? (code.getAttribute('data-enlighter-theme') || 'qj') : 'qj',
|
|
values: listboxValues(codeThemes),
|
|
},
|
|
{
|
|
type: 'textbox',
|
|
name: 'content',
|
|
label: i18n.codeLabel || '代码:',
|
|
value: code ? (code.textContent || '') : '',
|
|
multiline: true,
|
|
minHeight: Math.max(160, height - 115),
|
|
},
|
|
],
|
|
onsubmit: function (event) {
|
|
var content = String(event.data.content || '').replace(/\r\n/g, '\n');
|
|
if (!content) {
|
|
return;
|
|
}
|
|
var encoded = window.tinymce.html.Entities.encodeAllRaw(content);
|
|
var language = event.data.language === 'generic' ? '' :
|
|
' data-enlighter-language="' + escapeAttr(event.data.language) + '"';
|
|
var theme = event.data.theme === 'qj' ? '' :
|
|
' data-enlighter-theme="' + escapeAttr(event.data.theme) + '"';
|
|
var markup = '<pre contenteditable="false" class="enlighter-pre"><code class="gl"' +
|
|
language + theme + '>' + encoded + '</code></pre>';
|
|
if (selected) {
|
|
editor.dom.setOuterHTML(selected, markup);
|
|
} else {
|
|
editor.insertContent(markup + '<p></p>');
|
|
}
|
|
editor.nodeChanged();
|
|
editor.undoManager.add();
|
|
},
|
|
});
|
|
}
|
|
|
|
window.tinymce.PluginManager.add('aksrt_editor_tools', function (editor) {
|
|
bindCharacterCount(editor);
|
|
|
|
if (editorCfg.canUploadImage) {
|
|
editor.addButton('aksrt_image', {
|
|
text: '',
|
|
icon: 'image',
|
|
tooltip: i18n.insertImage || '插入图片',
|
|
onclick: function () {
|
|
createMediaModal(editor, 'image');
|
|
},
|
|
});
|
|
}
|
|
|
|
editor.addButton('aksrt_video', {
|
|
text: '',
|
|
icon: 'media',
|
|
tooltip: i18n.insertVideo || '插入视频',
|
|
onclick: function () {
|
|
createMediaModal(editor, 'video');
|
|
},
|
|
});
|
|
|
|
if (editorCfg.canUploadFile) {
|
|
editor.addButton('aksrt_file', {
|
|
text: '',
|
|
icon: 'upload',
|
|
tooltip: i18n.insertFile || '上传附件',
|
|
onclick: function () {
|
|
createMediaModal(editor, 'file');
|
|
},
|
|
});
|
|
}
|
|
|
|
editor.addButton('aksrt_quote', {
|
|
text: '',
|
|
icon: 'blockquote',
|
|
tooltip: i18n.quote || '引言',
|
|
type: 'menubutton',
|
|
stateSelector: '.quote_q',
|
|
menu: [
|
|
{ text: i18n.quoteGray || '灰色', onclick: function () { insertQuote(editor, ''); } },
|
|
{ text: i18n.quoteRed || '红色', onclick: function () { insertQuote(editor, 'qe_wzk_c-red'); } },
|
|
{ text: i18n.quoteBlue || '蓝色', onclick: function () { insertQuote(editor, 'qe_wzk_lan'); } },
|
|
{ text: i18n.quoteGreen || '绿色', onclick: function () { insertQuote(editor, 'qe_wzk_lv'); } },
|
|
],
|
|
});
|
|
|
|
editor.addButton('aksrt_precode', {
|
|
text: '',
|
|
icon: 'code',
|
|
tooltip: i18n.highlightCode || '高亮代码',
|
|
stateSelector: 'pre.enlighter-pre',
|
|
onclick: function () {
|
|
openCodeModal(editor);
|
|
},
|
|
});
|
|
|
|
if (editorCfg.canHide) {
|
|
var menu = [
|
|
{
|
|
text: i18n.replyVisible || '回复可见',
|
|
type: 'reply',
|
|
open: '[reply]',
|
|
close: '[/reply]',
|
|
},
|
|
{
|
|
text: i18n.loginVisible || '登录可见',
|
|
type: 'login',
|
|
open: '[aksrt_hide mode="login"]',
|
|
close: '[/aksrt_hide]',
|
|
},
|
|
{
|
|
text: i18n.vipVisible || 'VIP 可见',
|
|
type: 'vip',
|
|
open: '[vip]',
|
|
close: '[/vip]',
|
|
},
|
|
];
|
|
if (editorCfg.canPay) {
|
|
menu.push({
|
|
text: i18n.payVisible || '付费可见',
|
|
type: 'payshow',
|
|
open: '[payshow]',
|
|
close: '[/payshow]',
|
|
});
|
|
}
|
|
menu = menu.map(function (item) {
|
|
return {
|
|
text: item.text,
|
|
onclick: function () {
|
|
insertHiddenContent(editor, item);
|
|
},
|
|
};
|
|
});
|
|
editor.addButton('aksrt_hide', {
|
|
text: '',
|
|
icon: 'preview',
|
|
tooltip: i18n.hiddenContent || '隐藏内容',
|
|
type: 'menubutton',
|
|
stateSelector: '.tinymce-hide',
|
|
menu: menu,
|
|
});
|
|
}
|
|
});
|
|
})(window, document);
|