我正在Chrome中创建一个基于JS的书签,以在我单击书签时将过滤器INPUT添加到网页上的任何SELECT。我对具有IFRAME的页面进行了测试,只要浏览器对源策略感到满意,它就可以工作。请参阅下面的最低可行解决方案。
我在Salesforce中工作很多,并且经常使用多个页面,这些页面的下拉列表非常长(例如多达1000个选项),我想使用这种“快速”过滤解决方案。
问题是,SF在大多数后端页面上都使用了iframe,并且此代码不会从页面中选择IFRAME对象。
document.getElementsByTagName('IFRAME')
返回0个对象,即使我可以查看页面源并看到IFRAME。在我的测试中,“起源”情况下的“ get IFRAMEs”调用可以正常工作,它试图访问IFRAME中可能失败的内容。
我要获取的SELECT之一的路径如下:
html>正文> div> div>部分> div> force-aloha-page> div>iframe> html>正文> div> p>选择
我认为问题与该自定义标签force-aloha-page
有关。我尝试将其他元素放入该节点内,但没有成功。
这是一个错误吗?还是您无法遍历自定义标签内的DOM的预期行为?
我尝试创建一个递归脚本,该脚本试图通过遍历所有节点和子节点来获取所有元素,但是仍然无法在该自定义标记内获取。
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?
当前解决方案测试用例
这是我编写书签代码时使用的测试页。
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);
})();
下面的代码段应该起作用。
// 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/