Left: | ||
Right: |
OLD | NEW |
---|---|
1 /* | 1 /* |
2 * This file is part of Adblock Plus <http://adblockplus.org/>, | 2 * This file is part of Adblock Plus <http://adblockplus.org/>, |
3 * Copyright (C) 2006-2014 Eyeo GmbH | 3 * Copyright (C) 2006-2014 Eyeo GmbH |
4 * | 4 * |
5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
8 * | 8 * |
9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
13 * | 13 * |
14 * You should have received a copy of the GNU General Public License | 14 * You should have received a copy of the GNU General Public License |
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
16 */ | 16 */ |
17 | 17 |
18 var SELECTOR_GROUP_SIZE = 20; | 18 var SELECTOR_GROUP_SIZE = 20; |
19 | 19 |
20 // use Shadow DOM if available to don't mess with web pages that | |
21 // rely on the order of their own <style> tags. However | |
22 // the <shadow> element is broken in some Chrome 32 builds (#309) | |
23 // | |
24 // also Chrome 31-33 crashes in some situations on some pages when using | |
25 // ShadowDOM, e.g. when pressing tab key on Wikipedia and Facebook (#498) | |
26 // | |
27 // also we must not create the shadow root in the response callback passed | |
28 // to sendMessage(), otherwise Chrome breaks some websites (#450) | |
29 var shadow = null; | |
30 if ("webkitCreateShadowRoot" in document.documentElement && !/\bChrome\/3[1-3]\b /.test(navigator.userAgent)) | |
31 { | |
32 shadow = document.documentElement.webkitCreateShadowRoot(); | |
33 shadow.appendChild(document.createElement("shadow")); | |
34 } | |
35 | |
36 // Sets the currently used CSS rules for elemhide filters | |
37 function setElemhideCSSRules(selectors) | |
38 { | |
39 if (selectors.length == 0) | |
40 return; | |
41 | |
42 var style = document.createElement("style"); | |
43 style.setAttribute("type", "text/css"); | |
44 | |
45 if (shadow) | |
46 { | |
47 shadow.appendChild(style); | |
48 | |
49 try | |
50 { | |
51 document.querySelector("::content"); | |
52 | |
53 for (var i = 0; i < selectors.length; i++) | |
54 selectors[i] = "::content " + selectors[i]; | |
55 } | |
56 catch (e) | |
57 { | |
58 for (var i = 0; i < selectors.length; i++) | |
59 selectors[i] = "::-webkit-distributed(" + selectors[i] + ")"; | |
60 } | |
61 } | |
62 else | |
63 { | |
64 // Try to insert the style into the <head> tag, inserting directly under the | |
65 // document root breaks dev tools functionality: | |
66 // http://code.google.com/p/chromium/issues/detail?id=178109 | |
67 (document.head || document.documentElement).appendChild(style); | |
68 } | |
69 | |
70 // WebKit apparently chokes when the selector list in a CSS rule is huge. | |
71 // So we split the elemhide selectors into groups. | |
72 for (var i = 0; selectors.length > 0; i++) | |
73 { | |
74 var selector = selectors.splice(0, SELECTOR_GROUP_SIZE).join(", "); | |
75 style.sheet.insertRule(selector + " { display: none !important; }", i); | |
76 } | |
77 } | |
78 | |
79 var typeMap = { | |
80 "img": "IMAGE", | |
81 "input": "IMAGE", | |
82 "audio": "MEDIA", | |
83 "video": "MEDIA", | |
84 "frame": "SUBDOCUMENT", | |
85 "iframe": "SUBDOCUMENT" | |
86 }; | |
87 | |
88 function checkCollapse(event) | |
89 { | |
90 var target = event.target; | |
91 var tag = target.localName; | |
92 var expectedEvent = (tag == "iframe" || tag == "frame" ? "load" : "error"); | |
93 if (tag in typeMap && event.type == expectedEvent) | |
94 { | |
95 // This element failed loading, did we block it? | |
96 var url = target.src; | |
97 if (!url) | |
98 return; | |
99 | |
100 ext.backgroundPage.sendMessage( | |
101 { | |
102 type: "should-collapse", | |
103 url: url, | |
104 mediatype: typeMap[tag] | |
105 }, | |
106 | |
107 function(response) | |
108 { | |
109 if (response && target.parentNode) | |
110 { | |
111 // <frame> cannot be removed, doing that will mess up the frameset | |
112 if (tag == "frame") | |
113 target.style.setProperty("visibility", "hidden", "important"); | |
114 else | |
115 target.style.setProperty("display", "none", "important"); | |
116 } | |
117 } | |
118 ); | |
119 } | |
120 } | |
121 | |
122 // Converts relative to absolute URL | 20 // Converts relative to absolute URL |
123 // e.g.: foo.swf on http://example.com/whatever/bar.html | 21 // e.g.: foo.swf on http://example.com/whatever/bar.html |
124 // -> http://example.com/whatever/foo.swf | 22 // -> http://example.com/whatever/foo.swf |
125 function relativeToAbsoluteUrl(url) | 23 function relativeToAbsoluteUrl(url) |
126 { | 24 { |
127 // If URL is already absolute, don't mess with it | 25 // If URL is already absolute, don't mess with it |
128 if (!url || /^[\w\-]+:/i.test(url)) | 26 if (!url || /^[\w\-]+:/i.test(url)) |
129 return url; | 27 return url; |
130 | 28 |
131 // Leading / means absolute path | 29 // Leading / means absolute path |
132 // Leading // means network path | 30 // Leading // means network path |
133 if (url[0] == '/') | 31 if (url[0] == '/') |
134 { | 32 { |
135 if (url[1] == '/') | 33 if (url[1] == '/') |
136 return document.location.protocol + url; | 34 return document.location.protocol + url; |
137 else | 35 else |
138 return document.location.protocol + "//" + document.location.host + url; | 36 return document.location.protocol + "//" + document.location.host + url; |
139 } | 37 } |
140 | 38 |
141 // Remove filename and add relative URL to it | 39 // Remove filename and add relative URL to it |
142 var base = document.baseURI.match(/.+\//); | 40 var base = document.baseURI.match(/.+\//); |
143 if (!base) | 41 if (!base) |
144 return document.baseURI + "/" + url; | 42 return document.baseURI + "/" + url; |
145 return base[0] + url; | 43 return base[0] + url; |
146 } | 44 } |
147 | 45 |
148 function init() | 46 var typeMap = { |
47 "img": "IMAGE", | |
48 "input": "IMAGE", | |
49 "audio": "MEDIA", | |
50 "video": "MEDIA", | |
51 "frame": "SUBDOCUMENT", | |
52 "iframe": "SUBDOCUMENT" | |
53 }; | |
54 | |
55 function checkCollapse(element) | |
Wladimir Palant
2014/05/30 11:45:17
Please move this function and the typeMap declarat
Sebastian Noack
2014/05/30 12:31:11
Done.
| |
149 { | 56 { |
150 // Make sure this is really an HTML page, as Chrome runs these scripts on just about everything | 57 var tag = element.localName; |
151 if (!(document.documentElement instanceof HTMLElement)) | 58 if (tag in typeMap) |
152 return; | 59 { |
60 // This element failed loading, did we block it? | |
61 var url = element.src; | |
62 if (!url) | |
63 return; | |
153 | 64 |
154 document.addEventListener("error", checkCollapse, true); | 65 ext.backgroundPage.sendMessage( |
155 document.addEventListener("load", checkCollapse, true); | 66 { |
67 type: "should-collapse", | |
68 url: url, | |
69 mediatype: typeMap[tag] | |
70 }, | |
156 | 71 |
72 function(response) | |
73 { | |
74 if (response && element.parentNode) | |
75 { | |
76 // <frame> cannot be removed, doing that will mess up the frameset | |
77 if (tag == "frame") | |
78 element.style.setProperty("visibility", "hidden", "important"); | |
79 else | |
80 element.style.setProperty("display", "none", "important"); | |
81 } | |
82 } | |
83 ); | |
84 } | |
85 } | |
86 | |
87 function checkExcpetionKey() | |
Wladimir Palant
2014/05/30 11:45:17
Excpetion => Exception
Sebastian Noack
2014/05/30 12:31:11
Done.
| |
88 { | |
157 var attr = document.documentElement.getAttribute("data-adblockkey"); | 89 var attr = document.documentElement.getAttribute("data-adblockkey"); |
158 if (attr) | 90 if (attr) |
159 ext.backgroundPage.sendMessage({type: "add-key-exception", token: attr}); | 91 ext.backgroundPage.sendMessage({type: "add-key-exception", token: attr}); |
92 } | |
93 | |
94 function init(document) | |
95 { | |
96 // use Shadow DOM if available to don't mess with web pages that | |
97 // rely on the order of their own <style> tags. However | |
98 // the <shadow> element is broken in some Chrome 32 builds (#309) | |
99 // | |
100 // also Chrome 31-33 crashes in some situations on some pages when using | |
101 // ShadowDOM, e.g. when pressing tab key on Wikipedia and Facebook (#498) | |
102 // | |
103 // also we must not create the shadow root in the response callback passed | |
104 // to sendMessage(), otherwise Chrome breaks some websites (#450) | |
105 var shadow = null; | |
106 if ("webkitCreateShadowRoot" in document.documentElement && !/\bChrome\/3[1-3] \b/.test(navigator.userAgent)) | |
107 { | |
108 shadow = document.documentElement.webkitCreateShadowRoot(); | |
109 shadow.appendChild(document.createElement("shadow")); | |
110 } | |
111 | |
112 // Sets the currently used CSS rules for elemhide filters | |
113 var setElemhideCSSRules = function(selectors) | |
114 { | |
115 if (selectors.length == 0) | |
116 return; | |
117 | |
118 var style = document.createElement("style"); | |
119 style.setAttribute("type", "text/css"); | |
120 | |
121 if (shadow) | |
122 { | |
123 shadow.appendChild(style); | |
124 | |
125 try | |
126 { | |
127 document.querySelector("::content"); | |
128 | |
129 for (var i = 0; i < selectors.length; i++) | |
130 selectors[i] = "::content " + selectors[i]; | |
131 } | |
132 catch (e) | |
133 { | |
134 for (var i = 0; i < selectors.length; i++) | |
135 selectors[i] = "::-webkit-distributed(" + selectors[i] + ")"; | |
136 } | |
137 } | |
138 else | |
139 { | |
140 // Try to insert the style into the <head> tag, inserting directly under t he | |
141 // document root breaks dev tools functionality: | |
142 // http://code.google.com/p/chromium/issues/detail?id=178109 | |
143 (document.head || document.documentElement).appendChild(style); | |
144 } | |
145 | |
146 var setRules = function() | |
147 { | |
148 // The sheet property might not exist yet if the | |
149 // <style> element was created for a sub frame | |
150 if (!style.sheet) | |
151 { | |
152 setTimeout(setRules, 0); | |
153 return; | |
154 } | |
155 | |
156 // WebKit apparently chokes when the selector list in a CSS rule is huge. | |
157 // So we split the elemhide selectors into groups. | |
158 for (var i = 0; selectors.length > 0; i++) | |
159 { | |
160 var selector = selectors.splice(0, SELECTOR_GROUP_SIZE).join(", "); | |
161 style.sheet.insertRule(selector + " { display: none !important; }", i); | |
162 } | |
163 }; | |
164 | |
165 setRules(); | |
166 }; | |
167 | |
168 document.addEventListener("error", function(event) | |
169 { | |
170 checkCollapse(event.target); | |
171 }, true); | |
172 | |
173 document.addEventListener("load", function(event) | |
174 { | |
175 if (/^i?frame$/.test(event.target.localName)) | |
176 { | |
177 checkCollapse(event.target); | |
178 | |
179 // Chrome doesn't run our content script on anonymous frames. | |
180 // So we have to apply element hiding and collapsing from the | |
181 // parent frame, when an anonymous sub frame loaded. | |
182 if (/^(javascript:|$)/.test(event.target.src) && /\bChrome\//.test(navigat or.userAgent)) | |
183 { | |
184 var contentDocument = event.target.contentDocument; | |
185 | |
186 if (contentDocument.documentElement instanceof HTMLElement) | |
187 { | |
188 init(contentDocument); | |
189 | |
190 for (tagName in typeMap) | |
191 Array.prototype.forEach.call(contentDocument.getElementsByTagName(ta gName), checkCollapse); | |
192 } | |
193 } | |
194 } | |
195 }, true); | |
160 | 196 |
161 ext.backgroundPage.sendMessage({type: "get-selectors"}, setElemhideCSSRules); | 197 ext.backgroundPage.sendMessage({type: "get-selectors"}, setElemhideCSSRules); |
162 } | 198 } |
163 | 199 |
164 // In Chrome 18 the document might not be initialized yet | 200 if (document.documentElement instanceof HTMLElement) |
Wladimir Palant
2014/05/30 11:45:17
Why did you remove the failsafe? It was added back
Sebastian Noack
2014/05/30 12:31:11
I tested in Chrome 34 and Chrome 30, and it seems
| |
165 if (document.documentElement) | 201 { |
166 init(); | 202 checkExcpetionKey(); |
167 else | 203 init(document); |
Wladimir Palant
2014/05/30 11:45:17
Why pass in the document which is a global variabl
Sebastian Noack
2014/05/30 12:31:11
It is not always called with the global document.
| |
168 window.setTimeout(init, 0); | 204 } |
OLD | NEW |