光看標題可能會有點抽象。先說起因,最近看到了這個帖子,https://sstm.moe/topic/358822-不用打开检查界面就通过外链插入音视频控件的脚本直接获取全民k歌电脑网页音频源文件的脚本(基于tampermonkey插件)/,所以去找了下可以準確地將元素插入到相應的編輯框的方法,然後就發現了這個
首先看下圖,隨便找個回覆點修改,可以看到在 CKEDITOR.instances 中有兩個object,帶有id的是最底下新回覆的,先不用管它。comment_value 則是修改回覆用的編輯框。
這時候在"其他媒體" >> "插入外部圖片"中輸入鏈接可以正常插入圖片,到這裡都沒有問題。
但假如在保持之前的修改編輯器存在的情況下再打開另一個,可以看到CKEDITOR.instances 中仍然只有兩個object
這時在任意的修改框裡插入圖片,圖都會出現在最後打開的那一個裡面
問題講完了,再說說原因,首先可以看到這個編輯框是基於CKEditor的,在創建的時候會調用CKEDITOR.add,在CKEDITOR.instances[b.name] = b; 這裡用name 作為key把editor寫入到CKEDITOR.instances裡面(也就是一開始展示的那個)。
但是所有的修改框都叫comment_value,所以在CKEDITOR.instances中只能找到最後創建的那一個。
CKEDITOR.add = function(b) {
function h() {
CKEDITOR.currentInstance == b && (CKEDITOR.currentInstance = null,
CKEDITOR.fire("currentInstance"))
}
CKEDITOR.instances[b.name] = b;
b.on("focus", function() {
CKEDITOR.currentInstance != b && (CKEDITOR.currentInstance = b,
CKEDITOR.fire("currentInstance"))
});
b.on("blur", h);
b.on("destroy", h);
CKEDITOR.fire("instance", null, b)
}
其二就是在插入圖片時也是在CKEDITOR.instances裡面去找的,可以看var editor = CKEDITOR.instances[$(this.scope).data('editorid')]; 這一句,最終導致在同時存在多個修改框時,只會找到最後創建的那一個
insertLink: function(e) {
var url = this.scope.find('[data-role="linkURL"]').val().replace(/'/g, '%27').replace(/"/g, '%22').replace(/</g, '%3C').replace(/>/g, '%3E');
if (!url) {
$(this.scope).find('.ipsFieldRow.ipsFieldRow_fullWidth').addClass('ipsFieldRow_error');
return;
} else {
$(this.scope).find('.ipsFieldRow.ipsFieldRow_fullWidth').removeClass('ipsFieldRow_error');
}
$(this.scope).find('.elLinkError').remove();
if (!url.match(/^[a-z]+\:\/\//i) && !url.match(/^mailto\:/i) && !url.match(/^\#/)) {
url = 'http://' + url.replace(/^\/*/, '');
}
var editor = CKEDITOR.instances[$(this.scope).data('editorid')];
var selection = editor.getSelection();
if (!_.isUndefined(editor._linkBookmarks)) {
selection.selectBookmarks(editor._linkBookmarks);
delete editor._linkBookmarks;
}
var selectedElement = selection.getSelectedElement();
if (selectedElement && selectedElement.is('img')) {
var selectedElement = $(selection.getSelectedElement().$);
if (!selectedElement.parent().is('a')) {
var element = CKEDITOR.dom.element.createFromHtml("<a href='" + url + "'>" + selectedElement[0].outerHTML + "</a>");
editor.insertElement(element);
} else {
selectedElement.parent().attr('href', url).removeAttr('data-cke-saved-href');
}
this.scope.find('input.cEditorURL').val('');
this.trigger('closeDialog');
} else if (selectedElement && (selectedElement.is('a') && $(selection.getSelectedElement().$).children().is('img'))) {
selectedElement.setAttribute('href', url).removeAttribute('data-cke-saved-href');
this.scope.find('input.cEditorURL').val('');
this.trigger('closeDialog');
} else {
if ($(this.scope).data('image')) {
this.scope.find('[data-role="linkURL"]').addClass('ipsField_loading');
this.scope.find('[data-action="linkButton"]').prop('disabled', true);
var scope = this.scope;
var self = this;
var img = new Image();
img.onerror = function () {
scope.find('[data-role="linkURL"]').removeClass('ipsField_loading');
scope.find('[data-action="linkButton"]').prop('disabled', false);
scope.find('.ipsFieldRow.ipsFieldRow_fullWidth').addClass('ipsFieldRow_error');
}
;
img.onload = function () {
var ajaxUrl = editor.config.controller + '&do=validateLink'
if ($(this.scope).attr('data-image')) {
ajaxUrl += '&image=1';
}
ips.getAjax()(ajaxUrl, {
data: {
url: url,
width: img.width,
height: img.height,
image: 1
},
type: 'post'
}).done(function (response) {
if (response.embed) {
scope.find('[data-role="linkURL"]').removeClass('ipsField_loading');
scope.find('[data-action="linkButton"]').prop('disabled', false);
scope.find('input.cEditorURL').val('');
editor.insertHtml(response.preview);
self.trigger('closeDialog');
} else {
scope.find('[data-role="linkURL"]').removeClass('ipsField_loading');
scope.find('[data-action="linkButton"]').prop('disabled', false);
scope.find('.ipsFieldRow.ipsFieldRow_fullWidth').addClass('ipsFieldRow_error');
if (!_.isUndefined(response.errorMessage)) {
scope.find('.ipsFieldRow.ipsFieldRow_fullWidth').append("<span class='elLinkError ipsType_warning'>" + response.errorMessage + "</span>");
}
}
}).fail(function () {
scope.find('[data-role="linkURL"]').removeClass('ipsField_loading');
scope.find('[data-action="linkButton"]').prop('disabled', false);
scope.find('.ipsFieldRow.ipsFieldRow_fullWidth').addClass('ipsFieldRow_error');
});
}
img.src = url;
} else {
if (this.scope.find('[data-role="linkText"]').length) {
var title = this.scope.find('[data-role="linkText"]').val().replace(/ {2}/g, ' ');
if (!title) {
title = decodeURI(url);
}
title = title.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
var element = CKEDITOR.dom.element.createFromHtml("<a>" + title + "</a>");
} else {
element = selectedElement;
}
element.setAttribute('href', url);
editor.insertElement(element);
this.scope.find('input.cEditorURL').val('');
this.trigger('closeDialog');
}
}
}
我無法保證這裡說的東西完全正確,但是有打斷點檢查過,應該大致上是對的…吧?
順帶一提,如果你想寫腳本確實有需要用到這個editor,除了在CKEDITOR.instances裡面找,在這個div身上也可以拿到
順便再吐槽一下論壇的附件,我忍這東西很久了。直接點擊進行下載的時候不會指定文件名稱(明明在頁面上就有顯示文件名)。而且有些類型的文件不會直接下載,而是會跳轉到新頁面直接顯示(就算加了download attribute也不行。瀏覽器基於安全性的考慮,只有來自同一個來源的時候它才會生效)