/** * Front-submit TinyMCE tools matching the reference article editor. * * @package AKSRT */ (function (window, document) { 'use strict'; 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, '>'); } 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, fullUrl) { var safeUrl = validHttpUrl(url); var safeFullUrl = validHttpUrl(fullUrl || url); if (!safeUrl) { return ''; } var idAttr = attachmentId ? ' data-edit-file-id="' + Number(attachmentId) + '"' : ''; var altAttr = alt ? ' alt="' + escapeAttr(alt) + '"' : ' alt=""'; var fullAttr = safeFullUrl ? ' data-full-url="' + escapeAttr(safeFullUrl) + '"' : ''; return '

'; } function videoMarkup(url, attachmentId, name) { var safeUrl = validHttpUrl(url); if (!safeUrl) { return ''; } var idAttr = attachmentId ? ' data-edit-file-id="' + Number(attachmentId) + '"' : ''; return '
'; } 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-aksrt-file-id="' + Number(attachmentId) + '"' : ''; return '
' + '
' + '
' + '
' + escapeAttr(filename) + '
' + '
'; } 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 '
' + '
' + '
'; } function mediaUrl(type) { var configured = cfg.media && cfg.media[type] && cfg.media[type].url; if (configured) { return String(configured).indexOf('{type}') !== -1 ? String(configured).replace('{type}', encodeURIComponent(type)) : String(configured); } var base = cfg.mediaUrl || ''; if (String(base).indexOf('{type}') !== -1) return String(base).replace('{type}', encodeURIComponent(type)); if (base) return String(base).replace(/\/$/, '') + '/' + encodeURIComponent(type); return cfg.restUrl ? cfg.restUrl.replace(/\/$/, '') + '/front-submit/media/' + encodeURIComponent(type) : ''; } function currentPostId() { var field = document.querySelector('#aksrt-submit-form input[name="posts_id"]'); return Number((field && field.value) || cfg.postId || 0) || 0; } 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); var uploadUrl = String(upload.url); if (currentPostId()) { uploadUrl += (uploadUrl.indexOf('?') === -1 ? '?' : '&') + 'post_id=' + encodeURIComponent(String(currentPostId())); } return fetch(uploadUrl, { 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 || (payload.data && payload.data.message))) || i18n.error || '文件上传失败'); } return payload; }); }); } function imageBatchLimit() { // 0 = 不限制(沿用默认 100 的选取上限),1 = 不允许批量上传。 var configured = Number(cfg.imageUploadMultiple); if (!isFinite(configured) || configured <= 0) { return { multiple: true, maxItems: 100 }; } if (configured === 1) { return { multiple: false, maxItems: 1 }; } return { multiple: true, maxItems: Math.min(configured, 100) }; } function mediaDefinition(type) { if (type === 'video') return { title: i18n.insertVideo || '插入视频', mineTab: i18n.mineVideo || '我的视频', uploadTab: i18n.uploadVideo || '上传视频', externalTab: i18n.externalVideo || '外链视频', embedTab: i18n.embedVideo || '嵌入视频', accept: 'video/*', multiple: false, maxItems: 1, 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 || '上传附件', mineTab: i18n.mineFile || '我的文件', uploadTab: i18n.uploadFile || '上传附件', externalTab: i18n.externalFile || '输入地址', accept: '*/*', multiple: false, maxItems: 1, canUpload: !!editorCfg.canUploadFile && !!((cfg.uploads || {}).resource), canEmbed: false, select: i18n.selectFile || '选择或拖入附件', hint: i18n.fileUploadHint || '上传完成后自动插入正文', externalHint: i18n.externalFileHint || '请填写附件地址:', }; var batch = imageBatchLimit(); return { title: i18n.insertImage || '插入图片', mineTab: i18n.mineImage || '我的图片', uploadTab: i18n.uploadImage || '上传图片', externalTab: i18n.externalImage || '外链图片', accept: 'image/gif,image/jpeg,image/png,image/webp', multiple: batch.multiple, maxItems: batch.maxItems, canUpload: !!editorCfg.canUploadImage && !!((cfg.uploads || {}).image), canEmbed: false, select: i18n.selectImages || '选择或拖入图片', hint: i18n.imageUploadHint || '可批量选择,上传完成后自动插入正文', externalHint: i18n.externalImageHint || '每行填写一个图片地址:', }; } function mediaMarkup(type, item) { var id = item.attachment_id || item.id; if (type === 'video') return videoMarkup(item.url, id, item.filename || item.name || ''); if (type === 'file') return fileMarkup(item.url, id, item.filename || item.name || ''); return imageMarkup(item.large_url || item.url, id, item.name || item.title || '', item.url); } function formatBytes(value) { var size = Number(value) || 0, units = ['B', 'KB', 'MB', 'GB'], index = 0; if (!size) return ''; while (size >= 1024 && index < units.length - 1) { size /= 1024; index += 1; } return (index ? size.toFixed(size >= 10 ? 0 : 1) : String(Math.round(size))) + ' ' + units[index]; } function extension(item) { var name = String(item.filename || item.name || item.url || ''), match = name.match(/\.([a-z0-9]{1,8})(?:[?#].*)?$/i); return match ? match[1].toUpperCase() : String(item.subtype || item.type || '').toUpperCase(); } function closeMediaModal(force) { if (!activeModal) return; if (activeModal.uploading && !force) { notify(i18n.uploadingClose || '上传中,请稍候再关闭', 'warning'); return; } document.removeEventListener('keydown', activeModal.onKeydown); if (activeModal.searchTimer) window.clearTimeout(activeModal.searchTimer); activeModal.root.remove(); if (activeModal.previousFocus && typeof activeModal.previousFocus.focus === 'function') activeModal.previousFocus.focus(); activeModal = null; document.body.classList.remove('aksrt-editor-media-open'); } function openMediaModal(options) { options = options || {}; if (activeModal) { closeMediaModal(); if (activeModal) return; } var type = ['image', 'video', 'file'].indexOf(options.type) === -1 ? 'image' : options.type; var definition = mediaDefinition(type), multiple = options.multiple === undefined ? definition.multiple : !!options.multiple; var maxItems = Math.max(1, Number(options.maxItems || (multiple ? definition.maxItems : 1)) || 1); if (!multiple) maxItems = 1; var allowExternal = options.allowExternal !== false; var allowEmbed = definition.canEmbed && options.allowEmbed !== false; var canUpload = definition.canUpload && options.canUpload !== false; 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 = '' + '
' + '

' + escapeAttr(options.title || definition.title) + '

' + '
' + (canUpload ? '' : '') + (allowExternal ? '' : '') + (allowEmbed && type === 'video' ? '' : '') + '
' + '
' + '' + '
' + (canUpload ? '
' : '') + (allowExternal ? '

' + escapeAttr(definition.externalHint) + '

' : '') + (allowEmbed && type === 'video' ? '

' + escapeAttr(i18n.embedVideoHint || '请输入嵌入地址或者直接粘贴 iframe 嵌入代码:') + '

' : '') + '
'; document.body.appendChild(root); document.body.classList.add('aksrt-editor-media-open'); var state = { root: root, uploading: false, loading: false, requestId: 0, searchTimer: null, previousFocus: document.activeElement, page: 0, totalPages: 0, search: '', items: [], pinned: [], selected: [], exclude: [] }; var list = root.querySelector('[data-editor-media-list]'), status = root.querySelector('[data-editor-media-status]'), more = root.querySelector('[data-editor-media-more]'); var confirm = root.querySelector('[data-editor-media-confirm]'); var search = root.querySelector('[data-editor-media-search]'), fileInput = root.querySelector('[data-editor-media-files]'), uploadButton = root.querySelector('[data-editor-media-upload]'); var selection = root.querySelector('[data-editor-media-selection]'), progress = root.querySelector('[data-editor-media-progress]'), drop = root.querySelector('.aksrt-editor-media__drop'), files = []; function statusText(text, cls) { if (!status) return; status.className = 'aksrt-editor-media__status' + (cls ? ' is-' + cls : ''); status.textContent = text || ''; } function itemId(item) { return Number(item.attachment_id || item.id || 0); } function selectedIndex(id) { return state.selected.findIndex(function (item) { return itemId(item) === id; }); } function renderSelection() { if (selection) selection.textContent = files.length ? (multiple ? (i18n.selectedFiles || '已选择 %d 个文件').replace('%d', String(files.length)) : files[0].name) : ''; if (uploadButton) uploadButton.disabled = !files.length || state.uploading; } function renderItem(item) { var id = itemId(item), index = selectedIndex(id), chosen = index !== -1, disabled = !chosen && state.selected.length >= maxItems; var label = escapeAttr(item.filename || item.name || item.title || item.url || ''); var itemType = String(item.type || type); var hasImagePreview = itemType === 'image' && (item.thumbnail_url || item.medium_url || item.url); var thumb = hasImagePreview ? '' + label + '' : ''; var meta = type === 'image' ? label : label + (extension(item) ? ' · ' + escapeAttr(extension(item)) : '') + (formatBytes(item.filesizeInBytes) ? ' · ' + escapeAttr(formatBytes(item.filesizeInBytes)) : ''); return ''; } function renderList() { if (!list) return; list.innerHTML = state.items.length ? state.items.map(renderItem).join('') : ''; if (more) more.hidden = state.loading || state.page >= state.totalPages || !state.items.length; if (confirm) { confirm.hidden = !multiple || !state.selected.length; confirm.disabled = state.uploading; confirm.textContent = (i18n.confirmSelected || '确认选择(%d)').replace('%d', String(state.selected.length)); } } function finish(value) { if (state.uploading) return; if (typeof options.onSelect === 'function') options.onSelect(multiple ? value.slice() : value[0]); closeMediaModal(true); } function selectItem(item) { var id = itemId(item), index = selectedIndex(id); if (index !== -1) state.selected.splice(index, 1); else { if (!multiple) state.selected = []; if (state.selected.length >= maxItems) return; state.selected.push(item); } renderList(); if (!multiple && state.selected.length) finish(state.selected); } function addItems(items) { (items || []).forEach(function (item) { var id = itemId(item); if (!id) return; if (state.exclude.indexOf(id) === -1) state.exclude.push(id); if (!state.items.some(function (old) { return itemId(old) === id; })) state.items.unshift(item); if (!state.pinned.some(function (old) { return itemId(old) === id; })) state.pinned.unshift(item); }); renderList(); } function activateTab(name) { var tab = root.querySelector('[data-editor-media-tab="' + name + '"]'); if (tab) tab.click(); } function request(page, replace) { var url = mediaUrl(type); if (!url) { statusText(i18n.mediaUnavailable || '媒体库暂不可用', 'error'); return; } if (replace) { state.items = state.search.length >= 2 ? [] : state.pinned.slice(); state.page = 0; } state.loading = true; renderList(); statusText(i18n.loading || '加载中…', 'loading'); var requestId = ++state.requestId; var params = new URLSearchParams(); params.set('paged', String(page)); params.set('per_page', '48'); if (currentPostId()) params.set('post_id', String(currentPostId())); if (state.search.length >= 2) params.set('search', state.search); if (state.exclude.length) params.set('exclude', state.exclude.join(',')); fetch(url + (url.indexOf('?') === -1 ? '?' : '&') + params.toString(), { credentials: 'same-origin', headers: { 'X-WP-Nonce': cfg.restNonce || '' } }).then(function (response) { return response.json().catch(function () { return {}; }).then(function (payload) { if (!response.ok) throw new Error((payload && (payload.message || (payload.data && payload.data.message))) || i18n.error || '加载失败'); return payload || {}; }); }).then(function (payload) { if (requestId !== state.requestId) return; var incoming = Array.isArray(payload.items) ? payload.items : []; if (replace) state.items = state.search.length >= 2 ? [] : state.pinned.slice(); incoming.forEach(function (item) { if (state.exclude.indexOf(itemId(item)) === -1) state.items.push(item); }); state.page = Number(payload.page || page); state.totalPages = Number(payload.total_pages || 0); state.loading = false; renderList(); statusText(state.items.length ? '' : (i18n.emptyMedia || '暂无媒体文件'), state.items.length ? '' : 'empty'); }).catch(function (error) { if (requestId !== state.requestId) return; state.loading = false; renderList(); statusText(error.message || i18n.mediaError || '媒体加载失败', 'error'); }); } function setFiles(nextFiles) { var candidates = Array.prototype.slice.call(nextFiles || []); var uploadKey = type === 'file' ? 'resource' : type; var upload = (cfg.uploads || {})[uploadKey] || {}; var rejected = false; files = candidates.filter(function (file) { var valid = acceptsFile(file, type) && (!upload.maxSize || file.size <= upload.maxSize); rejected = rejected || !valid; return valid; }); if (rejected) notify(i18n.invalidFile || i18n.fileTooLarge || '部分文件类型或大小不符合要求', 'warning'); if (!multiple) files = files.slice(0, 1); if (files.length > maxItems) { files = files.slice(0, maxItems); notify((i18n.maxMediaItems || '最多选择 %d 个文件').replace('%d', String(maxItems)), 'warning'); } renderSelection(); } function uploadSelected() { if (!files.length || state.uploading) return; state.uploading = true; renderSelection(); renderList(); if (uploadButton) uploadButton.textContent = i18n.uploading || '正在上传…'; if (progress) { progress.hidden = false; progress.textContent = i18n.uploading || '正在上传…'; progress.style.setProperty('--aksrt-upload-progress', '0%'); } var complete = 0, total = files.length, nextIndex = 0, results = []; var toastId = 'aksrt-front-submit-editor-media-toast'; notify(i18n.uploading || '正在上传…', 'load', '', toastId); function worker() { var index = nextIndex++; if (index >= total) return Promise.resolve(); return uploadMedia(files[index], type).then(function (item) { results[index] = { item: item }; }).catch(function (error) { results[index] = { error: error }; }).finally(function () { complete += 1; if (progress) progress.style.setProperty('--aksrt-upload-progress', Math.round((complete / total) * 100) + '%'); }).then(worker); } var workers = Math.min(4, total); Promise.all(Array.apply(null, Array(workers)).map(function () { return worker(); })).then(function () { var items = results.map(function (result) { return result && result.item; }).filter(Boolean); var failure = results.find(function (result) { return result && result.error; }); addItems(items); state.selected = items.slice(0, maxItems); state.uploading = false; renderList(); files = []; renderSelection(); if (items.length) notify(i18n.uploaded || '上传成功', 'success', 5, toastId); if (failure) notify(failure.error.message || i18n.error || '部分文件上传失败', 'danger', 5, toastId); if (!items.length) return; if (!multiple) finish(state.selected); else activateTab('mine'); }).finally(function () { state.uploading = false; renderList(); if (uploadButton) { uploadButton.disabled = !files.length; uploadButton.textContent = i18n.confirmUpload || '确认上传'; } if (progress) progress.hidden = true; }); } function externalSelect() { var textarea = root.querySelector('[data-editor-media-urls]'), urls = String(textarea ? textarea.value : '').split(/\r?\n/).map(function (url) { var valid = validHttpUrl(url); return valid ? { url: valid } : null; }).filter(Boolean).slice(0, maxItems); if (!urls.length) { notify(i18n.invalidMediaUrl || '请填写有效地址', 'warning'); return; } finish(urls); } function embedSelect() { var input = root.querySelector('[data-editor-media-embed]'), html = embedVideoMarkup(input ? input.value : ''); if (!html) { notify(i18n.invalidVideoUrl || '请填写有效的视频嵌入地址', 'warning'); return; } if (typeof options.onEmbed === 'function') options.onEmbed(html); else if (typeof options.onSelect === 'function') options.onSelect({ embed: html }); closeMediaModal(true); } 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 (button) { var active = button === tab; button.classList.toggle('is-active', active); button.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); }); if (name === 'mine' && state.page === 0) request(1, true); return; } var itemButton = event.target.closest('[data-editor-media-item]'); if (itemButton && !itemButton.disabled) { var item = state.items.find(function (entry) { return itemId(entry) === Number(itemButton.getAttribute('data-editor-media-item')); }); if (item) selectItem(item); return; } if (event.target.closest('[data-editor-media-clear]')) { if (search) search.value = ''; window.clearTimeout(state.searchTimer); state.search = ''; request(1, true); return; } if (event.target.closest('[data-editor-media-confirm]')) { if (state.selected.length) finish(state.selected); return; } if (event.target.closest('[data-editor-media-more]')) { if (!state.loading) request(state.page + 1, false); return; } if (event.target.closest('[data-editor-media-external]')) { externalSelect(); return; } if (event.target.closest('[data-editor-media-embed-submit]')) { embedSelect(); return; } if (event.target.closest('[data-editor-media-upload]')) uploadSelected(); }); if (search) search.addEventListener('input', function () { state.search = String(search.value || '').trim(); window.clearTimeout(state.searchTimer); state.searchTimer = window.setTimeout(function () { if (state.search.length === 1) { state.items = []; state.page = 0; state.totalPages = 0; state.loading = false; renderList(); statusText(i18n.searchMin || '请输入至少 2 个字符进行搜索', 'empty'); return; } request(1, true); }, 600); }); 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(); }; state.onKeydown = onKeydown; activeModal = state; document.addEventListener('keydown', onKeydown); var focusTarget = root.querySelector('.aksrt-editor-media__dialog'); if (focusTarget) focusTarget.focus({ preventScroll: true }); request(1, true); } window.AksrtSubmitMedia = { open: openMediaModal, close: function () { closeMediaModal(); }, upload: uploadMedia }; function selectedContent(editor) { var content = String(editor.selection.getContent() || '').trim(); return content ? '

' + content + '

' : '

' + escapeAttr(i18n.hiddenPlaceholder || '隐藏内容') + '

'; } function insertHiddenContent(editor, item) { var node = editor.selection.getNode(); var content = selectedContent(editor); var suffix = '

'; 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( '
' + '

' + escapeAttr(item.open) + '

' + '
' + content + '
' + '

' + escapeAttr(item.close) + '

' + '
' + 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 ? '

' + content + '

' : '

'; } editor.insertContent( '
' + content + '

' ); 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 = '
' + encoded + '
'; if (selected) { editor.dom.setOuterHTML(selected, markup); } else { editor.insertContent(markup + '

'); } editor.nodeChanged(); editor.undoManager.add(); }, }); } function registerEditorTools() { if (!window.tinymce || !window.tinymce.PluginManager || window.aksrtSubmitEditorToolsRegistered) { return false; } window.aksrtSubmitEditorToolsRegistered = true; window.tinymce.PluginManager.add('aksrt_editor_tools', function (editor) { bindCharacterCount(editor); if (editorCfg.canUploadImage) { var imageBatch = imageBatchLimit(); editor.addButton('aksrt_image', { text: '', icon: 'image', tooltip: i18n.insertImage || '插入图片', onclick: function () { window.AksrtSubmitMedia.open({ type: 'image', multiple: imageBatch.multiple, maxItems: imageBatch.maxItems, onSelect: function (items) { editor.insertContent(items.map(function (item) { return mediaMarkup('image', item); }).join('') + '

'); editor.nodeChanged(); }, }); }, }); } editor.addButton('aksrt_video', { text: '', icon: 'media', tooltip: i18n.insertVideo || '插入视频', onclick: function () { window.AksrtSubmitMedia.open({ type: 'video', multiple: false, onSelect: function (item) { editor.insertContent(mediaMarkup('video', item) + '

'); editor.nodeChanged(); }, onEmbed: function (html) { editor.insertContent(html + '

'); editor.nodeChanged(); }, }); }, }); if (editorCfg.canUploadFile) { editor.addButton('aksrt_file', { text: '', icon: 'upload', tooltip: i18n.insertFile || '上传附件', onclick: function () { window.AksrtSubmitMedia.open({ type: 'file', multiple: false, onSelect: function (item) { editor.insertContent(mediaMarkup('file', item) + '

'); editor.nodeChanged(); }, }); }, }); } 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, }); } }); return true; } registerEditorTools(); if (!window.aksrtSubmitEditorToolsRegistered) { var retryCount = 0; var retryRegistration = function () { if (registerEditorTools()) { return; } retryCount += 1; if (retryCount < 100) { window.setTimeout(retryRegistration, 50); } }; retryRegistration(); } })(window, document);