Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: chrome/content/ui/ehh-composer.js

Issue 6525035187535872: issue #390 - Integrate parts of Element Hiding Helper functionality into Adblock Plus (Closed)
Patch Set: Created July 18, 2014, 12:54 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | chrome/content/ui/ehh-composer.xul » ('j') | chrome/locale/en-US/ehh-composer.dtd » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * This Source Code is subject to the terms of the Mozilla Public License
3 * version 2.0 (the "License"). You can obtain a copy of the License at
4 * http://mozilla.org/MPL/2.0/.
5 */
6
7 let {Prefs} = require("prefs");
8 let {FilterStorage} = require("filterStorage");
9 let {Filter} = require("filterClasses");
10
11 let domainData;
12 let nodeData;
13 let selectedNode = null;
14 let advancedMode = false;
15 let treeView = null;
16 let stylesheetData;
17 let previewStyle = null;
18 let doc;
19
20 /*******************
21 * NodeData object *
22 *******************/
23
24 function NodeData(node, parentNode) {
25 this.tagName = {value: node.tagName, checked: false};
26
27 if (typeof parentNode == "undefined")
28 parentNode = (node.parentNode && node.parentNode.nodeType == node.ELEMENT_NO DE ? new NodeData(node.parentNode) : null);
29 this.parentNode = parentNode;
30
31 var prevSibling = node.previousSibling;
32 while (prevSibling && prevSibling.nodeType != node.ELEMENT_NODE)
33 prevSibling = prevSibling.previousSibling;
34 this.prevSibling = (prevSibling ? new NodeData(prevSibling, this.parentNode) : null);
35
36 if (parentNode && !prevSibling)
37 this.firstChild = {checked: false};
38
39 var nextSibling = node.nextSibling;
40 while (nextSibling && nextSibling.nodeType != node.ELEMENT_NODE)
41 nextSibling = nextSibling.nextSibling;
42 if (parentNode && !nextSibling)
43 this.lastChild = {checked: false};
44
45 this.attributes = [];
46 for (var i = 0; i < node.attributes.length; i++) {
47 var attribute = node.attributes[i];
48 var data = {name: attribute.name, value: attribute.value, selected: attribut e.value, checked: false};
49 if (data.name == "id" || data.name == "class")
50 this.attributes.unshift(data);
51 else
52 this.attributes.push(data);
53 }
54
55 if (this.attributes.length >= 2 && this.attributes[1].name == "id") {
56 // Make sure ID attribute comes first
57 var tmp = this.attributes[1];
58 this.attributes[1] = this.attributes[0];
59 this.attributes[0] = tmp;
60 }
61
62 this.customCSS = {selected: "", checked: false};
63 }
64
65 /*******************
66 * TreeView object *
67 *******************/
68
69 function TreeView(tree) {
70 var origView = tree.view;
71 this.getRowProperties = TreeView_getRowProperties;
72 this.getCellProperties = TreeView_getCellProperties;
73
74 createQIProxy(this, origView);
75
76 for (var key in origView) {
77 if (this.hasOwnProperty(key))
78 continue;
79
80 createPropertyProxy(this, origView, key);
81 }
82
83 tree.view = this;
84 }
85
86 function createQIProxy(obj, orig) {
87 obj.QueryInterface = function(iid) {
88 var impl = orig.QueryInterface(iid);
89 if (impl != orig)
90 throw Cr.NS_ERROR_NO_INTERFACE;
91
92 return obj;
93 };
94 }
95
96 function createPropertyProxy(obj, orig, key) {
97 if (typeof orig[key] == "function") {
98 obj[key] = function() {
99 return orig[key].apply(orig, arguments);
100 };
101 }
102 else {
103 obj.__defineGetter__(key, function() {
104 return orig[key];
105 });
106 obj.__defineSetter__(key, function(value) {
107 orig[key] = value;
108 });
109 }
110 }
111
112 function TreeView_getRowProperties(row) {
113 let properties = "selected-" + this.selection.isSelected(row);
114
115 var item = this.getItemAtIndex(row);
116 if (item && (item.nodeData.expression != "*" || item.nodeData == nodeData))
117 properties += " anchor";
118
119 return properties;
120 }
121
122 function TreeView_getCellProperties(row, col) {
123 this.getRowProperties(row);
124 }
125
126 /*********************
127 * General functions *
128 *********************/
129
130 function init() {
131 var element = window.arguments[0];
132 doc = element.ownerDocument;
133 var wnd = doc.defaultView;
134
135 // Check whether element hiding group is disabled
136 let subscription = FilterStorage.knownSubscriptions["~eh~"];
saroyanm 2014/07/18 13:14:41 In Element Hiding Helper we used -> AdblockPlus.ge
137 if (subscription && subscription.disabled)
138 {
139 let warning = document.getElementById("groupDisabledWarning");
140 if (/\?1\?/.test(warning.textContent))
141 warning.textContent = warning.textContent.replace(/\?1\?/g, subscription.t itle);
142 warning.hidden = false;
143 }
144
145 nodeData = new NodeData(element);
146 nodeData.tagName.checked = true;
147 if (nodeData.attributes.length > 0)
148 {
149 let maxLen = 0;
150 let bestAttr = null;
151 for (let i = 0; i < nodeData.attributes.length; i++)
152 {
153 let len = nodeData.attributes[i].value.length;
154 if ((nodeData.attributes[i].name == "id" || nodeData.attributes[i].name == "class") && len)
155 {
156 len = 0x7FFFFFFF;
157 nodeData.tagName.checked = false;
158 }
159 if (len > maxLen)
160 {
161 maxLen = len;
162 bestAttr = nodeData.attributes[i];
163 }
164 }
165 if (bestAttr)
166 {
167 bestAttr.selected = bestAttr.value;
168 bestAttr.checked = true;
169 }
170 }
171
172 let domain = wnd.location.hostname;
173 let selectedDomain;
174 switch (Prefs.ehh_composer_defaultDomain)
175 {
176 case 0:
177 selectedDomain = "";
178 break;
179 case 1:
180 try
181 {
182 // EffectiveTLDService will throw for IP addresses, just go to the next case then
183 let effectiveTLD = Cc["@mozilla.org/network/effective-tld-service;1"].ge tService(Ci.nsIEffectiveTLDService);
184 selectedDomain = effectiveTLD.getPublicSuffixFromHost(domain);
185 break;
186 } catch (e) {}
187 case 2:
188 try
189 {
190 // EffectiveTLDService will throw for IP addresses, just go to the next case then
191 let effectiveTLD = Cc["@mozilla.org/network/effective-tld-service;1"].ge tService(Ci.nsIEffectiveTLDService);
192 selectedDomain = effectiveTLD.getBaseDomainFromHost(domain);
193 break;
194 } catch (e) {}
195 case 3:
196 selectedDomain = domain.replace(/^www\./, "");
197 break;
198 default:
199 selectedDomain = domain;
200 break;
201 }
202 domainData = {value: domain, selected: selectedDomain};
203
204 fillDomains(domainData);
205 fillNodes(nodeData);
206 setAdvancedMode(document.documentElement.getAttribute("advancedMode") == "true ");
207 updateExpression();
208
209 setTimeout(function() {
210 document.getElementById("domainGroup").selectedItem.focus();
211 if (document.getElementById("preview").checked)
212 togglePreview(true);
213 }, 0);
214 }
215
216 function updateExpression()
217 {
218 var curNode = nodeData;
219
220 function escapeName(name)
221 {
222 return name.replace(/([^\w\-])/g, "\\$1")
223 .replace(/\\([\{\}])/g, escapeChar);
224 }
225
226 while (curNode)
227 {
228 let expression = (curNode.tagName.checked ? curNode.tagName.value : "");
229
230 for (var i = 0; i < curNode.attributes.length; i++)
231 {
232 var attr = curNode.attributes[i];
233
234 if (attr.checked) {
235 var escapedName = escapeName(attr.name);
236 if (attr.selected != "")
237 {
238 var op = "*=";
239 if (attr.selected == attr.value)
240 op = "=";
241 else if (attr.value.substr(0, attr.selected.length) == attr.selected)
242 op = "^=";
243 else if (attr.value.substr(attr.value.length - attr.selected.length) = = attr.selected)
244 op = "$=";
245
246 let useFallback = false;
247 if (attr.name == "id" && op == "=")
248 expression += "#" + escapeName(attr.selected).replace(/^([^a-zA-Z\\] )/, escapeChar).replace(/\\(\s)$/, escapeChar);
249 else if (attr.name == "class" && /\S/.test(attr.selected))
250 {
251 let knownClasses = {};
252 for each (let cls in attr.value.split(/\s+/))
253 knownClasses[cls] = true;
254
255 let classes = attr.selected.split(/\s+/).filter(function(cls) cls != "");
256 if (classes.every(function(cls) knownClasses.hasOwnProperty(cls)))
257 expression += "." + classes.map(escapeName).join(".");
258 else
259 useFallback = true;
260 }
261 else
262 useFallback = true;
263
264 if (useFallback)
265 {
266 var escapedValue = attr.selected.replace(/(["\\])/g, '\\$1')
267 .replace(/([\{\}])/g, escapeChar)
268 .replace(/([^\S ])/g, escapeChar);
269 expression += "[" + escapedName + op + '"' + escapedValue + '"' + "] ";
270 }
271 }
272 else
273 {
274 expression += "[" + escapedName + "]";
275 }
276 }
277 }
278
279 if (curNode.customCSS.checked && curNode.customCSS.selected != "")
280 {
281 expression += curNode.customCSS.selected
282 .replace(/([\{\}])/g, escapeChar)
283 .replace(/([^\S ])/g, escapeChar);
284 }
285
286 if ("firstChild" in curNode && curNode.firstChild.checked)
287 expression += ":first-child";
288 if ("lastChild" in curNode && curNode.lastChild.checked)
289 expression += ":last-child";
290
291 if (expression == "")
292 expression = "*";
293
294 curNode.expression = expression;
295
296 if (curNode.prevSibling)
297 curNode = curNode.prevSibling;
298 else
299 curNode = curNode.parentNode;
300 }
301
302 let expression = nodeData.expression;
303
304 var isParent = false;
305 var isRemoteParent = false;
306 var siblingCount = 0;
307 var firstRun = true;
308
309 var curData = nodeData;
310 while (curData) {
311 if (!firstRun && curData.expression != "*") {
312 var parentRelation = "";
313 if (isRemoteParent)
314 parentRelation = " ";
315 else if (isParent)
316 parentRelation = " > ";
317
318 var siblingRelation = "";
319 for (var i = 0; i < siblingCount; i++)
320 siblingRelation += "* + ";
321 siblingRelation = siblingRelation.replace(/^\*/, '');
322
323 var relation;
324 if (parentRelation != "" && siblingRelation != "")
325 relation = siblingRelation + "*" + parentRelation;
326 else if (parentRelation != "")
327 relation = parentRelation;
328 else
329 relation = siblingRelation;
330
331 expression = curData.expression + relation + expression;
332
333 isParent = false;
334 isRemoteParent = false;
335 siblingCount = 0;
336 }
337 firstRun = false;
338
339 if (curData.prevSibling) {
340 siblingCount++;
341 curData = curData.prevSibling;
342 }
343 else if (curData.parentNode) {
344 siblingCount = 0;
345 if (isParent)
346 isRemoteParent = true;
347 else
348 isParent = true;
349 curData = curData.parentNode;
350 }
351 else
352 curData = null;
353 }
354
355 stylesheetData = expression + "{display: none !important;}";
356 expression = domainData.selected + "##" + expression;
357
358 document.getElementById("expression").value = expression;
359
360 var tree = document.getElementById("nodes-tree");
361 if (tree.view && tree.view.selection)
362 tree.treeBoxObject.invalidateRow(tree.view.selection.currentIndex);
363
364 if (previewStyle)
365 previewStyle.textContent = stylesheetData;
366 }
367
368 function escapeChar(dummy, match)
369 {
370 return "\\" + match.charCodeAt(0).toString(16) + " ";
371 }
372
373 function fillDomains(domainData) {
374 var list = document.getElementById("domainGroup");
375
376 var commandHandler = function() {
377 changeDomain(this);
378 };
379
380 var node = document.createElement("radio");
381 node.setAttribute("label", list.getAttribute("_labelnone"));
382 node.setAttribute("value", "");
383 node.addEventListener("command", commandHandler, false);
384 if (domainData.selected == "")
385 node.setAttribute("selected", "true");
386 list.appendChild(node);
387
388 var parts = domainData.value.split(".");
389 if (parts[0] == "")
390 parts.shift();
391
392 for (var i = 1; i <= parts.length; i++) {
393 if (parts[parts.length - i] == "")
394 continue;
395
396 var curDomain = parts.slice(parts.length - i).join(".");
397
398 node = document.createElement("radio");
399 node.setAttribute("label", curDomain)
400 node.setAttribute("value", curDomain);
401 node.addEventListener("command", commandHandler, false);
402 if (domainData.selected == curDomain)
403 node.setAttribute("selected", "true");
404 list.appendChild(node);
405 }
406 }
407
408 function fillNodes(nodeData) {
409 var curContainer = document.createElement("treechildren");
410 var curChildren = null;
411 while (nodeData) {
412 var id = "";
413 var className = "";
414 var i = 0;
415 if (nodeData.attributes.length > i && nodeData.attributes[i].name == "id")
416 id = nodeData.attributes[i++].value;
417 if (nodeData.attributes.length > i && nodeData.attributes[i].name == "class" )
418 className = nodeData.attributes[i++].value;
419
420 var item = document.createElement("treeitem");
421 var row = document.createElement("treerow");
422
423 var cell = document.createElement("treecell");
424 cell.setAttribute("label", nodeData.tagName.value);
425 row.appendChild(cell);
426
427 cell = document.createElement("treecell");
428 cell.setAttribute("label", id);
429 row.appendChild(cell);
430
431 cell = document.createElement("treecell");
432 cell.setAttribute("label", className);
433 row.appendChild(cell);
434
435 item.appendChild(row);
436 item.nodeData = nodeData;
437
438 if (curChildren) {
439 item.appendChild(curChildren);
440 item.setAttribute("container", "true");
441 item.setAttribute("open", "true");
442 }
443 curChildren = null;
444
445 if (curContainer.firstChild)
446 curContainer.insertBefore(item, curContainer.firstChild);
447 else
448 curContainer.appendChild(item);
449
450 if (nodeData.prevSibling)
451 nodeData = nodeData.prevSibling;
452 else if (nodeData.parentNode) {
453 curChildren = curContainer;
454 curContainer = document.createElement("treechildren");
455 nodeData = nodeData.parentNode;
456 }
457 else
458 nodeData = null;
459 }
460
461 var tree = document.getElementById("nodes-tree");
462 var body = document.getElementById("nodes-tree-children");
463 while (curContainer.firstChild)
464 body.appendChild(curContainer.firstChild);
465 }
466
467 function createAttribute(template, attr, text, value)
468 {
469 template = E(template == "basic" ? "basicAttributeTemplate" : "advancedAttribu teTemplate");
470
471 let result = template.cloneNode(true);
472 result.removeAttribute("id");
473 result.removeAttribute("hidden");
474 result.attr = attr;
475
476 let checkbox = result.getElementsByClassName("checkbox")[0];
477 checkbox.setAttribute("checked", attr.checked);
478 checkbox.attr = attr;
479
480 let label = result.getElementsByClassName("label");
481 if (label.length)
482 {
483 label = label[0];
484 label.setAttribute("value", text);
485
486 let randID = "i" + String(Math.random()).replace(/\D/g, "");
487 checkbox.setAttribute("id", randID);
488 label.setAttribute("control", randID);
489 }
490 else
491 checkbox.setAttribute("label", text);
492
493 let textbox = result.getElementsByClassName("textbox");
494 if (textbox.length)
495 {
496 textbox = textbox[0];
497 textbox.setAttribute("value", value);
498 textbox.attr = attr;
499 }
500
501 return result;
502 }
503
504 function fillAttributes(nodeData)
505 {
506 selectedNode = nodeData;
507
508 let list = document.getElementById("attributes-list");
509 while(list.firstChild)
510 list.removeChild(list.firstChild);
511
512 // Add tag name entry
513 let node = createAttribute("basic", nodeData.tagName, list.getAttribute("_labe ltagname") + " " + nodeData.tagName.value);
514 list.appendChild(node);
515
516 // Add first/last child entries
517 if (advancedMode && "firstChild" in nodeData)
518 {
519 node = createAttribute("basic", nodeData.firstChild, list.getAttribute("_lab elfirstchild"));
520 list.appendChild(node);
521 }
522 if (advancedMode && "lastChild" in nodeData)
523 {
524 node = createAttribute("basic", nodeData.lastChild, list.getAttribute("_labe llastchild"));
525 list.appendChild(node);
526 }
527
528 // Add attribute entries
529 for (let i = 0; i < nodeData.attributes.length; i++)
530 {
531 let attr = nodeData.attributes[i];
532 node = createAttribute(advancedMode ? "advanced" : "basic", attr, attr.name + ": " + attr.value, attr.selected);
533 list.appendChild(node);
534 }
535
536 if (advancedMode)
537 {
538 // Add custom CSS entry
539 node = createAttribute("advanced", nodeData.customCSS, list.getAttribute("_l abelcustom"), nodeData.customCSS.selected);
540 list.appendChild(node);
541 }
542 }
543
544 function togglePreview(preview) {
545 if (preview) {
546 if (!previewStyle || !previewStyle.parentNode) {
547 previewStyle = doc.createElementNS("http://www.w3.org/1999/xhtml", "style" );
548 previewStyle.setAttribute("type", "text/css");
549 doc.documentElement.appendChild(previewStyle);
550 }
551 previewStyle.textContent = stylesheetData;
552 }
553 else {
554 try
555 {
556 if (previewStyle && previewStyle.parentNode)
557 previewStyle.parentNode.removeChild(previewStyle);
558 }
559 catch (e)
560 {
561 // if the window was closed (reloaded) we end up with dead object referenc e
562 // https://bugzilla.mozilla.org/show_bug.cgi?id=695480
563 // just ignore this case
564 }
565 previewStyle = null;
566 }
567 }
568
569 function changeDomain(node) {
570 domainData.selected = node.getAttribute("value");
571 updateExpression();
572 }
573
574 function toggleAttr(node) {
575 node.attr.checked = node.checked;
576 updateExpression();
577 }
578
579 function setSelectedAttrValue(node) {
580 node.attr.selected = node.value;
581 if (node.attr.checked)
582 updateExpression();
583 }
584
585 function setAdvancedMode(mode) {
586 advancedMode = mode;
587
588 var dialog = document.documentElement;
589 dialog.setAttribute("advancedMode", advancedMode);
590
591 var button = dialog.getButton("disclosure");
592 button.setAttribute("label", dialog.getAttribute(advancedMode ? "buttonlabeldi sclosure_off" : "buttonlabeldisclosure_on"));
593
594 fillAttributes(nodeData);
595
596 if (advancedMode) {
597 setTimeout(function() {
598 var tree = document.getElementById("nodes-tree");
599
600 if (!treeView)
601 treeView = new TreeView(tree);
602
603 if (selectedNode) {
604 // Expand all containers
605 var items = tree.getElementsByTagName("treeitem");
606 for (var i = 0; i < items.length; i++)
607 if (items[i].getAttribute("container") == "true")
608 items[i].setAttribute("open", "true");
609
610 tree.treeBoxObject.ensureRowIsVisible(tree.view.rowCount - 1);
611 tree.view.selection.select(tree.view.rowCount - 1);
612 }
613 }, 0);
614 }
615 }
616
617 function updateNodeSelection() {
618 var tree = document.getElementById("nodes-tree");
619 var selection = tree.view.selection;
620 if (selection.count < 1)
621 return;
622
623 var min = {};
624 selection.getRangeAt(0, min, {});
625
626 var item = tree.view
627 .QueryInterface(Ci.nsITreeContentView)
628 .getItemAtIndex(min.value);
629 if (!item || !item.nodeData)
630 return;
631
632 fillAttributes(item.nodeData);
633 }
634
635 function addExpression()
636 {
637 let filter = Filter.fromText(Filter.normalize(document.getElementById("express ion").value));
saroyanm 2014/07/18 13:14:41 In Element Hiding Helper we used "AdblockPlus.addP
638 if (filter)
639 {
640 filter.disabled = false;
641 FilterStorage.addFilter(filter);
642 }
643
644 togglePreview(false);
645 }
OLDNEW
« no previous file with comments | « no previous file | chrome/content/ui/ehh-composer.xul » ('j') | chrome/locale/en-US/ehh-composer.dtd » ('J')

Powered by Google App Engine
This is Rietveld