Невозможно получить доступ к IFRAME внутри пользовательского тега через DOM через JavaScript - PullRequest
0 голосов
/ 26 сентября 2019

Я много работаю в Salesforce, и у меня есть несколько страниц, с которыми я работаю регулярно, с очень длинными выпадающими списками (например, до 1000 вариантов), и я хотел создать решение для быстрой фильтрации, которое находит SELECT настраница, и добавляет к нему поле фильтра.(Подробнее об этом ниже)

SF использует IFRAME на большинстве всех внутренних страниц, и этот код НЕ будет выбирать объекты IFRAME со страницы.

document.getElementsByTagName('IFRAME') возвращает 0 объектов, несмотря на то, что я могу посмотреть на исходный код страницы и увидеть IFRAME.Похоже, это не связано с какой-либо межсайтовой безопасностью, так как в моем тестировании вызов getElementsByTagName('IFRAME') привел бы объект iframe в «плохую» исходную ситуацию, но попытка получить доступ к чему-либо внутри IFRAME не удалась.В этом случае он даже не получает IFRAME.

Путь к одному из SELECT, на который я хочу попасть, выглядит следующим образом:

html> body> div> div> section> div> force-aloha-page> div> iframe> html> body> div> p> select

Я думаю, что проблема связана с этим пользовательским тегом force-aloha-page.Я пытался получить другие элементы внутри этого узла, но безуспешно.В одной из строк ниже он выводит HTML DOM пользовательского тега, который показывает IFRAME.

Это ошибка?Или ожидаемое поведение, при котором вы не можете обойти DOM внутри пользовательских тегов?

Я пробовал некоторые сценарии в консоли Chrome, но это не давало бы мне видимость этого тега.

  • document.getElementsByClassName ("oneAlohaPage") [0] .childNodes.length
  • 1
  • document.getElementsByClassName ("oneAlohaPage") [0] .childNodes [0] .tagName
  • "FORCE-ALOHA-PAGE"
  • document.getElementsByTagName ("FORCE-ALOHA-PAGE"). Длина
  • 1
  • document.getElementsByTagName("FORCE-ALOHA-PAGE") [0] .childNodes.length
  • 0
  • document.getElementsByTagName ("FORCE-ALOHA-PAGE") [0] .innerHTML
  • ""
  • typeof document.getElementsByTagName ("FORCE-ALOHA-PAGE") [0]
  • "object"
  • document.getElementsByTagName ("FORCE-ALOHA-PAGE") [0]
  • <force-aloha-page data-data-rendering-service-uid=​"203" data-aura-rendered-by=​"505:​0" force-alohapage_alohapage-host>​<div force-alohapage_alohapage class=​"iframe-parent slds-template_iframe slds-card">​<iframe force-alohapage_alohapage height=​"100%" width=​"100%" scrolling=​"yes" allowtransparency=​"true" name=​"vfFrameId_1569557364522" title=​"Page Configuration" allowfullscreen=​"true" lang=​"en-US" allow=​"geolocation *;​ microphone *;​ camera *">​…​</iframe>​</div>​</force-aloha-page>​
  • document.getElementsByTagName ("FORCE-ALOHA-PAGE") [0] .parentNode
  • <div class=​"oneAlohaPage" data-aura-rendered-by=​"502:​0" data-aura-class=​"oneAlohaPage">​…​</div>​
  • document.getElementsByTagName ("FORCE-ALOHA-PAGE") [0] .firstChild
  • null
  • document.getElementsByTagName ("FORCE-ALOHA-PAGE")[0] .parentNode.firstChild
  • <force-aloha-page data-data-rendering-service-uid=​"203" data-aura-rendered-by=​"505:​0" force-alohapage_alohapage-host>​…​</force-aloha-page>​

Я попытался создать рекурсивный скрипт, который пытается получить все элементы путем обхода всех узлов и дочерних узлов, но по-прежнему не может попасть внутрьэтот пользовательский тег.

var allNodes = function(el) {
    var a = [];
    for(var i=0;i<el.childNodes.length;i++) {
        a.push(el.childNodes[i]);
        a = a.concat(allNodes(el.childNodes[i]));
    }
    return a;
};
var all = allNodes(document.body);
//The array will contain the 'force-aloha-page' element, but nothing inside it.

Есть ли какой-нибудь способ получить доступ к DOM внутри этих пользовательских тегов?

Текущее решение

Я создалЗакладка на основе JS в Chrome, чтобы добавить фильтр INPUT к любому SELECT на веб-странице, когда я нажимаю на закладку.Я проверил это на страницах с IFRAME, и, пока браузер доволен политикой происхождения, он работает.Это тестовая страница, которую я использовал, когда писал код закладки.

testpage1.html

<html>
<body>
<select>
    <option value="1">1</option>
    <option value="10">10</option>
    <option value="2">2</option>
    <option value="20">20</option>
</select>
<br /><br />
<select>
    <option value="Apples">Apples</option>
    <option value="Berries">Berries</option>
    <option value="Candies">Candies</option>
    <option value="Danishes">Danishes</option>
</select>
<br /><br />
<iframe src="testpage2.html"></iframe>
</body>
</html>

testpage2.html

<html>
<body>
<select>
    <option value="3">3</option>
    <option value="30">30</option>
    <option value="4">4</option>
    <option value="40">40</option>
</select>
<br /><br />
<select onchange="selectChange(this)">
    <option value="Eclaires">Eclaires</option>
    <option value="Frozen Custard">Frozen Custard</option>
    <option value="Grapes">Grapes</option>
    <option value="Heath Bar">Heath Bar</option>
</select>
<script type="text/javascript">
    function selectChange(el) {
        console.log("Select value: " + el.value);
    }
</script>
</body>
</html>

Код закладки (минимизирован):

При использовании Chrome щелкните правой кнопкой мыши на панели закладок, Добавить страницу, задайте имя страницы, например «Выбор фильтров», затем очистите URL-адрес и введите его.

javascript:(function(){var selects=function(d){var a=[],s=d.getElementsByTagName('SELECT'),b=d.getElementsByTagName('IFRAME');for(var i=0;i<s.length;i++)a.push(s[i]);for(var i=0;i<b.length;i++){try{a=a.concat(selects(b[i].contentWindow.document));}catch(e){console.log(e);}}return a;},blink=function(els,i){if(i>=els.length)return;var el=els[i],s=el.style,t=200,nb='3px solid blue',eb=s.border+'';el.scrollIntoView();s.border=nb;setTimeout(function(){s.border=eb;},t);setTimeout(function(){s.border=nb;},t*2);setTimeout(function(){s.border=eb;if(confirm("This one?")){filter(el);}else{blink(els,i+1);}},t*3);},opt=function(v,t,p){var y=document.createElement('OPTION');y.value=v;y.text=t;p.appendChild(y);},filter=function(el){console.log('Filtering...');var d=document,c=d.createElement('INPUT'),o=[];c.type='text';c.placeholder='Filter list';c.style.width=el.style.width;c.style.display='block';el.parentNode.insertBefore(c,el);c.onkeyup=function(ev){var j=c.value+'',h=el.options,x=0;if(o.length==0){for(var e=0;e<h.length;  e++){with(h[e]){o.push({'v':value,'t':text});}}}for(var g=h.length-1;g>=0;g--)el.remove(g);for(var i=0;i<o.length;  i++){if(j.length==0){opt(o[i].v,o[i].t,el);}else{if(match(o[i].t,j)){if(x==0) opt('','',el);opt(o[i].v,o[i].t,el);x++;}}}if(x>0) el.options[0].text='<'+x+' Match(es) Found>';};},match=function(a,b){a=(a+'').toLowerCase();b=(b+'').toLowerCase();if(b.indexOf('*')<0){return a.indexOf(b)>=0;}else{var r='.*',c=b.split('*');for(var i=0;i<c.length;i++){r+='.*'+(c[i].length>0?'('+c[i]+')':'');}r+='.*';return (new RegExp(r)).test(a);}},d=document,s=selects(d),v=[];for(var i=0;i<s.length;i++){if (window.getComputedStyle(s[i]).display !== 'none') v.push(s[i]);}console.log('SELECTs: '+s.length);console.log('Visible SELECTs: '+v.length);blink(v,0);})();

Код закладки (меньше минус):

javascript:(function(){
    //return an array of all selects in the main page or in iframes
    var selects=function(d){
        var a=[],
            s=d.getElementsByTagName('SELECT'),
            b=d.getElementsByTagName('IFRAME');
        for(var i=0;i<s.length;i++)
            a.push(s[i]);
        for(var i=0;i<b.length;i++){
            try{
                a=a.concat(selects(b[i].contentWindow.document));
            }catch(e){
                console.log(e);
            }
        }
        return a;
    },
    //makes the SELECT border blink and scrolls it into view
    blink=function(els,i){
        if(i>=els.length)return;
        var el=els[i],s=el.style,t=200,
            nb='3px solid blue',eb=s.border+'';
        el.scrollIntoView();
        s.border=nb;
        setTimeout(function(){s.border=eb;},t);
        setTimeout(function(){s.border=nb;},t*2);
        setTimeout(function(){
            s.border=eb;
            if(confirm("This one?")){
                filter(el);
            }else{
                blink(els,i+1);
            }
        },t*3);
    },
    //helper for creating options on a select
    opt=function(v,t,p){
        var y=document.createElement('OPTION');
        y.value=v;
        y.text=t;
        p.appendChild(y);
    },
    //creates the new filter input and adds it to the page
    filter=function(el){
        console.log('Filtering...');
        var d=document,c=d.createElement('INPUT'),o=[];
        c.type='text';
        c.placeholder='Filter list';
        c.style.width=el.style.width;
        c.style.display='block';
        el.parentNode.insertBefore(c,el);
        //filters the option list when something is typed
        c.onkeyup=function(ev){
            var j=c.value+'',h=el.options,x=0;
            if(o.length==0){
                for(var e=0;e<h.length; e++){
                    with(h[e]){
                        o.push({'v':value,'t':text});
                    }
                }
            }
            for(var g=h.length-1;g>=0;g--)el.remove(g);
            for(var i=0;i<o.length; i++){
                if(j.length==0){
                    opt(o[i].v,o[i].t,el);
                }else{
                    if(match(o[i].t,j)){
                        if(x==0) opt('','',el);
                        opt(o[i].v,o[i].t,el);
                        x++;
                    }
                }
            }
            if(x>0) el.options[0].text='<'+x+' Match(es) Found>';
        };
    },
    //determines if the option text matches the filter criteria, with wildcard support
    match=function(a,b){
        a=(a+'').toLowerCase();
        b=(b+'').toLowerCase();
        if(b.indexOf('*')<0){
            return a.indexOf(b)>=0;
        }else{
            var r='.*',c=b.split('*');
            for(var i=0;i<c.length;i++){
                r+='.*'+(c[i].length>0?'('+c[i]+')':'');
            }
            r+='.*';
            return (new RegExp(r)).test(a);
        }
    },
    d=document,s=selects(d),v=[];
    //gets only SELECTs that are visible on the page
    for(var i=0;i<s.length;i++){
        if (window.getComputedStyle(s[i]).display !== 'none') 
            v.push(s[i]);
    }
    console.log('SELECTs: '+s.length);
    console.log('Visible SELECTs: '+v.length);
    //Begin.
    blink(v,0);
})();

1 Ответ

0 голосов
/ 26 сентября 2019

Фрагмент ниже должен работать.

// Query all iframes in the DOM
var iframesNodes = document.querySelectorAll("iframe");

// Transfrom nodeList into an array
var iframes = Array.prototype.slice.call(iframesNodes);
console.log(iframes);

// Loop through all iframes
iframes.map(function(iframe){
  // Get the document of the current iframe
  var innerDoc = iframe.contentDocument || iframe.contentWindow.document;
  
  /* ... Then do what ever you want with the iframe document ... */
  innerDoc.body.style.backgroundColor = "#ff0000"
});
<exampletag>
    <iframe src="/" />
</exampletag>
 
<iframe src="/" />

Если вы хотите использовать пользовательские теги, вам следует прочитать это: https://www.smashingmagazine.com/2014/03/introduction-to-custom-elements/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...