简体   繁体   English

在iframe中扩展DOM元素的原型

[英]Extending prototype of DOM elements inside iframes

Consider this JS code. 考虑这个JS代码。 It basically initializes a CKEditor instance, waits 1 second, then runs codeToDebug 它基本上初始化一个CKEditor实例,等待1秒,然后运行codeToDebug

function codeToDebug(){
    setNodeListProp("attr", function customAttr(name, val){
        if(typeof val != "undefined"){
            this.setAttribute(name, val);
            return this;
        }
        else return this.getAttribute(name);
    });

    // secondary check: all elements on the current document HAVE `attr` method
    var all = document.querySelectorAll("*");
    for(var i = 0, len = all.length;i < len; i++) 
        if(!all[i].attr) // always false
            console.dir(all[i]); // never executes

    // logs undefined
    console.log(
            document.querySelector(".cke_wysiwyg_frame")
                .contentDocument
                .querySelector(".cke_editable").attr);
}

window.onload = function(){
    // Replace the <textarea id="editor1"> with a CKEditor
    // instance, using default configuration.
    CKEDITOR.editorConfig = function (config) {
        config.language = 'es';
        config.uiColor = '#F7B42C';
        config.height = 300;
        config.toolbarCanCollapse = true;

    };
    CKEDITOR.replace('editor1');
    // wait for async editor to load
    setTimeout(codeToDebug, 1000);
};

function setNodeListProp(prop, func){
    // in case of custom created array of Nodes, Array.prototype is necessary
    Array.prototype[prop] = NodeList.prototype[prop] = function() {
        var args = [].slice.call(arguments, 0);
        this.forEach(function(node) {
            func.apply(node, args);
        });
        return this;
    };

    Node.prototype[prop] = func;
}

The codeToDebug method extends the prototype of Node and NodeList with a method attr . codeToDebug方法使用方法attr扩展NodeNodeList的原型。 It then log s if attr is present on the .cke_editable textarea inside CKEditor's iframe. 然后log如果attr存在于CKEditor的iframe内的.cke_editable textarea上。 Surprisingly, it logs undefined . 令人惊讶的是,它记录undefined


My questions: 我的问题:

  1. Why isn't the prototype of Node s inside an iframe extended, when I am extending it in the main document? 当我在主文档中扩展时,为什么Node的原型不在iframe扩展中? (isn't a common global Node shared by all elements - regardless of where they are?) (不是所有元素共享的通用全局Node - 无论它们在哪里?)
  2. What is the best way to extend DOM of all elements - which are present on the webpage document, in its iframes, and its further nested iframes? 扩展所有元素的DOM的最佳方法是什么 - 它们存在于网页文档,iframe和其他嵌套的iframe中?

Notes: 笔记:

  1. I've already read Kangax's article (and Prototype's bugs) with extending DOM. 我已经通过扩展DOM阅读了Kangax的文章(以及Prototype的bug)。 But my use case is entirely different. 但我的用例完全不同。 I am only supposed to support latest versions of Chrome and Opera - both Webkit - as such I am NOT worried about conflicts. 我只应支持最新版本的Chrome和Opera - 两者都是Webkit - 因此我并不担心冲突。 So, please be assured I've taken the risks of extending the prototype in consideration, but this question is not about that. 所以,请放心,我已经考虑了扩展原型的风险,但这个问题与此无关。

  2. Here's the HTML (for some reason JSBin or Code Snippets won't show CKEditor): <script src="https://cdn.ckeditor.com/4.5.1/standard/ckeditor.js"></script><script>..ABOVE_JS_CODE..</script><textarea name="editor1" id="editor1" rows="10" cols="80"></textarea> (I locally created a index.html ) 这是HTML(由于某种原因,JSBin或Code Snippets不会显示CKEditor): <script src="https://cdn.ckeditor.com/4.5.1/standard/ckeditor.js"></script><script>..ABOVE_JS_CODE..</script><textarea name="editor1" id="editor1" rows="10" cols="80"></textarea> (我在本地创建了一个index.html

So, I myself wrote a function to solve this problem. 所以,我自己写了一个函数来解决这个问题。 Could be of benefit to anyone looking for a similar solution. 可能对寻求类似解决方案的任何人都有好处。

(function protoExtensionWork(){
    window.updateAllValuesPerWin = function(win){       
        for(var i = 0, count = protoExtensionNames.length; i < count; i++)
            setNodeListPropPerWindow(protoExtensionNames[i], protoExtensionFunctions[i], win);
    };

    // fill this up as per your requirement
    var protoExtensionNames = [], protoExtensionFunctions = [];

    function setNodeListPropPerWindow(prop, func, win){
        // in case of custom created array of Nodes, Array.prototype is necessary
        win.Array.prototype[prop] = win.NodeList.prototype[prop] = function() {
            var args = [].slice.call(arguments, 0);
            this.forEach(function(node) {
                func.apply(node, args);
            });
            return this;
        };

        win.Node.prototype[prop] = func;    
    }
})();

and this is the second piece of code for looking for iframe s: 这是寻找iframe的第二段代码:

function initiateIframeCheck(parentDoc){
    var iframes = parentDoc.querySelectorAll("iframe"),
        win, doc;

    iframes.forEach(function(iframe){       
        try{                
            doc = iframe.contentDocument;
            win = iframe.contentWindow;

            // make sure handler's not already attached
            if(!doc[UNIQ_KEY]){
                doc[UNIQ_KEY] = true;
                updateAllValuesPerWin(win);     
                setInterval(initiateIframeCheck, IFRAME_CHECK_TIMER, doc);
            }
        }catch(e){ // CORS
            //console.dir(e);               
        }
    });
}

Please anyone post an answer if they think they've a better and more apt method to achieve this task. 如果他们认为他们有更好,更贴切的方法来完成这项任务,请任何人发表答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM