| OLD | NEW |
| 1 /* | 1 /* |
| 2 * This Source Code is subject to the terms of the Mozilla Public License | 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 | 3 * version 2.0 (the "License"). You can obtain a copy of the License at |
| 4 * http://mozilla.org/MPL/2.0/. | 4 * http://mozilla.org/MPL/2.0/. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 const Cc = Components.classes; | 7 const Cc = Components.classes; |
| 8 const Ci = Components.interfaces; | 8 const Ci = Components.interfaces; |
| 9 const Cr = Components.results; | 9 const Cr = Components.results; |
| 10 const Cu = Components.utils; | 10 const Cu = Components.utils; |
| 11 | 11 |
| 12 Cu.import("resource://gre/modules/Services.jsm"); | 12 Cu.import("resource://gre/modules/Services.jsm"); |
| 13 | 13 |
| 14 function abprequire(module) | 14 function abprequire(module) |
| 15 { | 15 { |
| 16 let result = {}; | 16 let result = {}; |
| 17 result.wrappedJSObject = result; | 17 result.wrappedJSObject = result; |
| 18 Services.obs.notifyObservers(result, "adblockplus-require", module); | 18 Services.obs.notifyObservers(result, "adblockplus-require", module); |
| 19 return result.exports; | 19 return result.exports; |
| 20 } | 20 } |
| 21 | 21 |
| 22 let {Policy} = abprequire("contentPolicy"); | 22 let {Policy} = abprequire("contentPolicy"); |
| 23 let {RequestNotifier} = abprequire("requestNotifier"); | |
| 24 let {Filter} = abprequire("filterClasses"); | 23 let {Filter} = abprequire("filterClasses"); |
| 25 | 24 |
| 26 let policyGlobal = Cu.getGlobalForObject(Policy); | 25 let origShouldAllow = Policy.shouldAllow; |
| 27 let PolicyPrivate = null; | 26 if (!origShouldAllow) |
| 28 | |
| 29 if ("PolicyImplementation" in policyGlobal) // ABP 2.1+ with scope separation | |
| 30 PolicyPrivate = policyGlobal.PolicyImplementation; | |
| 31 else if ("require" in policyGlobal) // ABP 2.1+ without scope sepa
ration | |
| 32 PolicyPrivate = policyGlobal.require.scopes.contentPolicy.PolicyImplementation
; | |
| 33 else | |
| 34 window.close(); | 27 window.close(); |
| 35 | 28 |
| 36 let origShouldLoad = PolicyPrivate.shouldLoad; | |
| 37 let origProcessNode = Policy.processNode; | |
| 38 | |
| 39 let currentData = null; | |
| 40 let processingQueue = []; | 29 let processingQueue = []; |
| 41 let notifier = null; | 30 let notifier = null; |
| 42 | 31 |
| 43 // Randomize URI to work around bug 719376 | 32 // Randomize URI to work around bug 719376 |
| 44 let stringBundle = Services.strings.createBundle("chrome://abpwatcher/locale/glo
bal.properties?" + Math.random()); | 33 let stringBundle = Services.strings.createBundle("chrome://abpwatcher/locale/glo
bal.properties?" + Math.random()); |
| 45 | 34 |
| 46 let clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.
nsIClipboardHelper); | 35 let clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.
nsIClipboardHelper); |
| 47 | 36 |
| 48 function init() | 37 function init() |
| 49 { | 38 { |
| 50 let list = document.getElementById("list"); | 39 let list = document.getElementById("list"); |
| 51 list.view = treeView; | 40 list.view = treeView; |
| 52 list.focus(); | 41 list.focus(); |
| 53 | 42 |
| 54 treeView.addObserver(updateProcessingTime); | 43 treeView.addObserver(updateProcessingTime); |
| 55 updateProcessingTime(treeView, "refresh"); | 44 updateProcessingTime(treeView, "refresh"); |
| 56 | 45 |
| 57 // Make sure the tree view has correct filters | 46 // Make sure the tree view has correct filters |
| 58 document.getElementById("ignore-early").doCommand(); | |
| 59 document.getElementById("filterText").doCommand(); | 47 document.getElementById("filterText").doCommand(); |
| 60 | 48 |
| 61 notifier = new RequestNotifier(null, handleFilterHit); | 49 Policy.shouldAllow = replacementShouldAllow; |
| 62 | |
| 63 PolicyPrivate.shouldLoad = replacementShouldLoad; | |
| 64 Policy.processNode = replacementProcessNode; | |
| 65 setInterval(processQueue, 200); | 50 setInterval(processQueue, 200); |
| 66 } | 51 } |
| 67 | 52 |
| 68 function E(id) | 53 function E(id) |
| 69 { | 54 { |
| 70 return document.getElementById(id); | 55 return document.getElementById(id); |
| 71 } | 56 } |
| 72 | 57 |
| 73 function replacementShouldLoad(contentType, contentLocation, requestOrigin, node
, mimeTypeGuess, extra) | 58 function replacementShouldAllow({contentType, location, frames, isPrivate}) |
| 74 { | 59 { |
| 75 let startTime = null; | 60 let startTime = Date.now(); |
| 61 let currentData = { |
| 62 type: contentType, |
| 63 location: location, |
| 64 frames: frames, |
| 65 isPrivate: isPrivate |
| 66 }; |
| 67 let ret; |
| 68 |
| 76 try | 69 try |
| 77 { | 70 { |
| 78 currentData = {internal: false, earlyReturn: true, filters: []}; | 71 ret = origShouldAllow.apply(this, arguments); |
| 79 startTime = Date.now(); | |
| 80 | |
| 81 if (contentLocation) | |
| 82 currentData.location = contentLocation.spec; | |
| 83 if (requestOrigin) | |
| 84 currentData.origin = requestOrigin.spec; | |
| 85 | |
| 86 currentData.type = contentType; | |
| 87 } catch(e) {} | |
| 88 | |
| 89 let ret; | |
| 90 try | |
| 91 { | |
| 92 ret = origShouldLoad.apply(this, arguments); | |
| 93 return ret; | |
| 94 } | |
| 95 finally | |
| 96 { | |
| 97 if (startTime !== null) | |
| 98 currentData.processingTime = (Date.now() - startTime); | |
| 99 currentData.result = (ret == Ci.nsIContentPolicy.ACCEPT); | |
| 100 | |
| 101 processingQueue.push(currentData); | |
| 102 currentData = null; | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 function replacementProcessNode(wnd, node, contentType, location, collapse) | |
| 107 { | |
| 108 let startTime = null; | |
| 109 try | |
| 110 { | |
| 111 if (currentData && !("context" in currentData)) | |
| 112 { | |
| 113 currentData.earlyReturn = false; | |
| 114 currentData.context = node; | |
| 115 currentData.window = wnd; | |
| 116 currentData.internalType = contentType; | |
| 117 if (location) | |
| 118 currentData.internalLocation = location.spec; | |
| 119 } | |
| 120 else | |
| 121 { | |
| 122 // shouldLoad wasn't called - this isn't being called by content policy | |
| 123 let locationString = (location instanceof Filter ? location.text : locatio
n.spec); | |
| 124 | |
| 125 currentData = { | |
| 126 internal: true, | |
| 127 earlyReturn: false, | |
| 128 filters: [], | |
| 129 location: locationString, | |
| 130 internalLocation: locationString, | |
| 131 context: node, | |
| 132 window: wnd, | |
| 133 type: contentType, | |
| 134 internalType: contentType | |
| 135 }; | |
| 136 startTime = Date.now(); | |
| 137 } | |
| 138 } | |
| 139 catch(e) | |
| 140 { | |
| 141 Cu.reportError(e); | |
| 142 } | |
| 143 | |
| 144 let ret; | |
| 145 try | |
| 146 { | |
| 147 ret = origProcessNode.apply(this, arguments); | |
| 148 return ret; | 72 return ret; |
| 149 } | 73 } |
| 150 finally | 74 finally |
| 151 { | 75 { |
| 152 if (startTime !== null) | 76 if (startTime !== null) |
| 153 { | 77 { |
| 154 currentData.processingTime = (Date.now() - startTime); | 78 currentData.processingTime = (Date.now() - startTime); |
| 155 currentData.result = (ret == true); | 79 currentData.result = ret; |
| 80 currentData.filters = ret.hits.filter(h => h.filter).map(h => h.filter); |
| 156 | 81 |
| 157 processingQueue.push(currentData); | 82 processingQueue.push(currentData); |
| 158 currentData = null; | 83 currentData = null; |
| 159 } | 84 } |
| 160 } | 85 } |
| 161 } | 86 } |
| 162 | 87 |
| 163 function destroy() | 88 function destroy() |
| 164 { | 89 { |
| 165 if (notifier) | 90 if (origShouldAllow) |
| 166 notifier.shutdown(); | 91 Policy.shouldAllow = origShouldAllow; |
| 167 if (origShouldLoad) | |
| 168 PolicyPrivate.shouldLoad = origShouldLoad; | |
| 169 if (origProcessNode) | |
| 170 Policy.processNode = origProcessNode; | |
| 171 } | |
| 172 | |
| 173 function handleFilterHit(wnd, node, data) | |
| 174 { | |
| 175 if (data.filter && currentData) | |
| 176 currentData.filters.push(data.filter.text); | |
| 177 } | 92 } |
| 178 | 93 |
| 179 function processQueue() | 94 function processQueue() |
| 180 { | 95 { |
| 181 if (!processingQueue.length) | 96 if (!processingQueue.length) |
| 182 return; | 97 return; |
| 183 | 98 |
| 99 function stringify(value) |
| 100 { |
| 101 if (typeof value == "undefined" || value == null) |
| 102 return ""; |
| 103 else |
| 104 return String(value); |
| 105 } |
| 106 |
| 184 for each (let entry in processingQueue) | 107 for each (let entry in processingQueue) |
| 185 { | 108 { |
| 186 entry.cols = {}; | 109 entry.cols = { |
| 187 if (typeof entry.location != "undefined") | 110 address: stringify(entry.location), |
| 188 entry.cols.address = String(entry.location); | 111 type: stringify(entry.type), |
| 189 if (typeof entry.type != "undefined") | 112 result: stringBundle.GetStringFromName(entry.result && entry.result.allow
? "decision.allow" : "decision.block"), |
| 190 { | 113 origin: stringify(entry.frames && entry.frames[0] && entry.frames[0].locat
ion), |
| 191 entry.cols.type = String(entry.type); | 114 filter: stringify(entry.filters && entry.filters.join(", ")), |
| 192 try { | 115 time: stringify(entry.processingTime) |
| 193 // Nasty hack: try to get type name from ABP | 116 }; |
| 194 if (entry.type in Policy.localizedDescr) | |
| 195 entry.cols.type = String(Policy.localizedDescr[entry.type]); | |
| 196 } catch(e) {} | |
| 197 } | |
| 198 entry.cols.result = stringBundle.GetStringFromName(entry.result ? "decision.
allow" : "decision.block"); | |
| 199 if (typeof entry.context != "undefined") | |
| 200 entry.cols.context = (entry.context ? getNodeLabel(entry.context) : String
(entry.context)); | |
| 201 if (typeof entry.window != "undefined") | |
| 202 entry.cols.document = (entry.window ? getNodeLabel(entry.window) : String(
entry.window)); | |
| 203 if (typeof entry.origin != "undefined") | |
| 204 entry.cols.origin = String(entry.origin); | |
| 205 if (entry.filters.length) | |
| 206 entry.cols.filter = entry.filters.join(", "); | |
| 207 if (typeof entry.processingTime != "undefined") | |
| 208 entry.cols.time = String(entry.processingTime); | |
| 209 | |
| 210 let additional = []; | |
| 211 if (entry.internal) | |
| 212 additional.push(stringBundle.GetStringFromName("additional.internalInvocat
ion")); | |
| 213 if (typeof entry.internalType != "undefined" && entry.type != entry.internal
Type) | |
| 214 { | |
| 215 let internalType = String(entry.internalType); | |
| 216 try { | |
| 217 // Nasty hack: try to get type name from ABP | |
| 218 if (entry.internalType in Policy.localizedDescr) | |
| 219 internalType = String(Policy.localizedDescr[entry.internalType]); | |
| 220 } catch(e) {} | |
| 221 additional.push(stringBundle.formatStringFromName("additional.typeChanged"
, [internalType], 1)); | |
| 222 } | |
| 223 if (typeof entry.internalLocation != "undefined" && entry.location != entry.
internalLocation) | |
| 224 additional.push(stringBundle.formatStringFromName("additional.locationChan
ged", [String(entry.internalLocation)], 1)); | |
| 225 | |
| 226 if (additional.length > 0) | |
| 227 entry.cols.additional = additional.join(", "); | |
| 228 | |
| 229 treeView.add(entry); | 117 treeView.add(entry); |
| 230 } | 118 } |
| 231 | 119 |
| 232 processingQueue = []; | 120 processingQueue = []; |
| 233 } | 121 } |
| 234 | 122 |
| 235 function getNodeLabel(node) | |
| 236 { | |
| 237 try | |
| 238 { | |
| 239 if (node instanceof Ci.nsIDOMWindow) | |
| 240 return stringBundle.formatStringFromName("NodeLabel.window", [node.locatio
n.href], 1); | |
| 241 if (node instanceof Ci.nsIDOMDocument) | |
| 242 return stringBundle.formatStringFromName("NodeLabel.document", [node.URL],
1); | |
| 243 else if (node instanceof Ci.nsIDOMXULElement) | |
| 244 return stringBundle.formatStringFromName("NodeLabel.xulElement", [node.tag
Name], 1); | |
| 245 else if (node instanceof Ci.nsIDOMHTMLElement) | |
| 246 return stringBundle.formatStringFromName("NodeLabel.htmlElement", [node.ta
gName], 1); | |
| 247 else if (node instanceof Ci.nsIDOMSVGElement) | |
| 248 return stringBundle.formatStringFromName("NodeLabel.svgElement", [node.tag
Name], 1); | |
| 249 else if (node instanceof Ci.nsIDOMElement) | |
| 250 return stringBundle.formatStringFromName("NodeLabel.element", [node.tagNam
e], 1); | |
| 251 else | |
| 252 return stringBundle.formatStringFromName("NodeLabel.unknown", [String(node
)], 1); | |
| 253 } | |
| 254 catch (e) | |
| 255 { | |
| 256 Cu.reportError(e); | |
| 257 return stringBundle.formatStringFromName("NodeLabel.unknown", [""], 1); | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 function fillInTooltip(event) | 123 function fillInTooltip(event) |
| 262 { | 124 { |
| 263 let entry = treeView.getEntryAt(event.clientX, event.clientY); | 125 let entry = treeView.getEntryAt(event.clientX, event.clientY); |
| 264 if (!entry) | 126 if (!entry) |
| 265 return false; | 127 return false; |
| 266 | 128 |
| 267 let rows = document.getElementById("tooltip-rows"); | 129 let rows = document.getElementById("tooltip-rows"); |
| 268 while (rows.firstChild) | 130 while (rows.firstChild) |
| 269 rows.removeChild(rows.firstChild); | 131 rows.removeChild(rows.firstChild); |
| 270 | 132 |
| 271 let cols = document.getElementById("list").getElementsByTagName("treecol"); | 133 let cols = document.getElementById("list").getElementsByTagName("treecol"); |
| 272 for (let i = 0; i < cols.length; i++) | 134 for (let i = 0; i < cols.length; i++) |
| 273 { | 135 { |
| 274 let col = cols[i].id; | 136 let col = cols[i].id; |
| 275 if (col && col in entry.cols) | 137 if (col && col in entry.cols) |
| 276 { | 138 { |
| 277 let row = document.createElement("row"); | 139 let row = document.createElement("row"); |
| 278 | 140 |
| 279 let label = document.createElement("description"); | 141 let label = document.createElement("description"); |
| 280 label.setAttribute("class", "tooltip-label"); | 142 label.setAttribute("class", "tooltip-label"); |
| 281 label.setAttribute("value", cols[i].getAttribute("label")); | 143 label.setAttribute("value", cols[i].getAttribute("label")); |
| 282 row.appendChild(label); | 144 row.appendChild(label); |
| 283 | 145 |
| 284 let value = document.createElement("vbox"); | 146 let value = document.createElement("vbox"); |
| 285 setMultilineContent(value, entry.cols[col]); | 147 let data = entry.cols[col]; |
| 148 if (col == "origin") |
| 149 data = entry.frames.map(f => f.location).join("\n"); |
| 150 setMultilineContent(value, data); |
| 286 row.appendChild(value); | 151 row.appendChild(value); |
| 287 | 152 |
| 288 rows.appendChild(row); | 153 rows.appendChild(row); |
| 289 } | 154 } |
| 290 } | 155 } |
| 291 | 156 |
| 292 return true; | 157 return true; |
| 293 } | 158 } |
| 294 | 159 |
| 295 function updateContextMenu(event) | 160 function updateContextMenu(event) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 310 clipboardHelper.copyString(String(entry.location)); | 175 clipboardHelper.copyString(String(entry.location)); |
| 311 } | 176 } |
| 312 | 177 |
| 313 function copyFilters() | 178 function copyFilters() |
| 314 { | 179 { |
| 315 let entry = treeView.getCurrentEntry(); | 180 let entry = treeView.getCurrentEntry(); |
| 316 if (entry && entry.filters.length) | 181 if (entry && entry.filters.length) |
| 317 clipboardHelper.copyString(entry.filters.join("\n")); | 182 clipboardHelper.copyString(entry.filters.join("\n")); |
| 318 } | 183 } |
| 319 | 184 |
| 320 function setMultilineContent(box, text) { | 185 function setMultilineContent(box, text) |
| 321 // The following is sufficient in Gecko 1.9 but Gecko 1.8 fails on multiline | 186 { |
| 322 // text fields in tooltips | 187 let lines = text.split(/\n+/); |
| 323 // box.textContent = text.replace(/\S{80}(?=\S)/g, "$& "); | 188 for (let line of lines) |
| 324 | 189 { |
| 325 for (let i = 0; i < text.length; i += 80) { | |
| 326 let description = document.createElement("description"); | 190 let description = document.createElement("description"); |
| 327 description.setAttribute("value", text.substr(i, 80)); | 191 description.textContent = line.replace(/\S{80}(?=\S)/g, "$& "); |
| 328 box.appendChild(description); | 192 box.appendChild(description); |
| 329 } | 193 } |
| 330 } | 194 } |
| 331 | 195 |
| 332 var totalProcessingTime = 0; | 196 var totalProcessingTime = 0; |
| 333 function updateProcessingTime(view, operation, entry) | 197 function updateProcessingTime(view, operation, entry) |
| 334 { | 198 { |
| 335 if (operation == "add") | 199 if (operation == "add") |
| 336 totalProcessingTime += entry.processingTime; | 200 totalProcessingTime += entry.processingTime; |
| 337 else { | 201 else { |
| 338 totalProcessingTime = 0; | 202 totalProcessingTime = 0; |
| 339 for each (let entry in view.displayedItems) | 203 for each (let entry in view.displayedItems) |
| 340 totalProcessingTime += entry.processingTime; | 204 totalProcessingTime += entry.processingTime; |
| 341 } | 205 } |
| 342 | 206 |
| 343 let numItems = view.displayedItems.length; | 207 let numItems = view.displayedItems.length; |
| 344 | 208 |
| 345 let summary = document.getElementById("summary"); | 209 let summary = document.getElementById("summary"); |
| 346 let template = summary.getAttribute("_template"); | 210 let template = summary.getAttribute("_template"); |
| 347 summary.textContent = template.replace(/\*NUMITEMS\*/g, numItems).replace(/\*T
IME\*/, (totalProcessingTime / 1000).toFixed(3)); | 211 summary.textContent = template.replace(/\*NUMITEMS\*/g, numItems).replace(/\*T
IME\*/, (totalProcessingTime / 1000).toFixed(3)); |
| 348 } | 212 } |
| 349 | 213 |
| 350 var treeView = { | 214 var treeView = { |
| 351 currentItems: [], | 215 currentItems: [], |
| 352 displayedItems: [], | 216 displayedItems: [], |
| 353 _ignoreEarlyReturns: false, | |
| 354 _filterString: "", | 217 _filterString: "", |
| 355 _sortColumn: null, | 218 _sortColumn: null, |
| 356 _sortDirection: null, | 219 _sortDirection: null, |
| 357 boxObject: null, | 220 boxObject: null, |
| 358 atoms: {}, | 221 atoms: {}, |
| 359 observers: [], | 222 observers: [], |
| 360 | 223 |
| 361 // | 224 // |
| 362 // nsISupports implementation | 225 // nsISupports implementation |
| 363 // | 226 // |
| (...skipping 15 matching lines...) Expand all Loading... |
| 379 selection: null, | 242 selection: null, |
| 380 | 243 |
| 381 setTree: function(boxObject) | 244 setTree: function(boxObject) |
| 382 { | 245 { |
| 383 if (!boxObject) | 246 if (!boxObject) |
| 384 return; | 247 return; |
| 385 | 248 |
| 386 this.boxObject = boxObject; | 249 this.boxObject = boxObject; |
| 387 | 250 |
| 388 let atomService = Cc["@mozilla.org/atom-service;1"].getService(Ci.nsIAtomSer
vice); | 251 let atomService = Cc["@mozilla.org/atom-service;1"].getService(Ci.nsIAtomSer
vice); |
| 389 for each (let col in ["address", "type", "result", "context", "document", "o
rigin", "additional", "filter", "time"]) | 252 for each (let col in ["address", "type", "result", "origin", "filter", "time
"]) |
| 390 { | 253 { |
| 391 let atomStr = "col-" + col; | 254 let atomStr = "col-" + col; |
| 392 this.atoms[atomStr] = atomService.getAtom(atomStr); | 255 this.atoms[atomStr] = atomService.getAtom(atomStr); |
| 393 } | 256 } |
| 394 for each (let flag in ["selected", "blocked"]) | 257 for each (let flag in ["selected", "blocked"]) |
| 395 { | 258 { |
| 396 let atomStr = flag + "-true"; | 259 let atomStr = flag + "-true"; |
| 397 this.atoms[atomStr] = atomService.getAtom(atomStr); | 260 this.atoms[atomStr] = atomService.getAtom(atomStr); |
| 398 | 261 |
| 399 atomStr = flag + "-false"; | 262 atomStr = flag + "-false"; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 }, | 317 }, |
| 455 | 318 |
| 456 getRowProperties: function(row, properties) | 319 getRowProperties: function(row, properties) |
| 457 { | 320 { |
| 458 if (row < 0 || row >= this.displayedItems.length) | 321 if (row < 0 || row >= this.displayedItems.length) |
| 459 return ""; | 322 return ""; |
| 460 | 323 |
| 461 let entry = this.displayedItems[row]; | 324 let entry = this.displayedItems[row]; |
| 462 return this.generateProperties([ | 325 return this.generateProperties([ |
| 463 "selected-" + this.selection.isSelected(row), | 326 "selected-" + this.selection.isSelected(row), |
| 464 "blocked-" + !entry.result | 327 "blocked-" + !(entry.result && entry.result.allow) |
| 465 ], properties); | 328 ], properties); |
| 466 }, | 329 }, |
| 467 | 330 |
| 468 getCellProperties: function(row, col, properties) | 331 getCellProperties: function(row, col, properties) |
| 469 { | 332 { |
| 470 return this.getRowProperties(row, properties) + " " + this.getColumnProperti
es(col, properties); | 333 return this.getRowProperties(row, properties) + " " + this.getColumnProperti
es(col, properties); |
| 471 }, | 334 }, |
| 472 | 335 |
| 473 cycleHeader: function(col) | 336 cycleHeader: function(col) |
| 474 { | 337 { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 524 cycleCell: function() {}, | 387 cycleCell: function() {}, |
| 525 performAction: function() {}, | 388 performAction: function() {}, |
| 526 performActionOnRow: function() {}, | 389 performActionOnRow: function() {}, |
| 527 performActionOnCell: function() {}, | 390 performActionOnCell: function() {}, |
| 528 selectionChanged: function() {}, | 391 selectionChanged: function() {}, |
| 529 | 392 |
| 530 // | 393 // |
| 531 // Custom methods | 394 // Custom methods |
| 532 // | 395 // |
| 533 | 396 |
| 534 get ignoreEarlyReturns() | |
| 535 { | |
| 536 return this._ignoreEarlyReturns; | |
| 537 }, | |
| 538 set ignoreEarlyReturns(value) | |
| 539 { | |
| 540 this._ignoreEarlyReturns = value; | |
| 541 this.refilter(); | |
| 542 }, | |
| 543 | |
| 544 get filterString() | 397 get filterString() |
| 545 { | 398 { |
| 546 return this._filterString; | 399 return this._filterString; |
| 547 }, | 400 }, |
| 548 set filterString(value) | 401 set filterString(value) |
| 549 { | 402 { |
| 550 this._filterString = value.toLowerCase(); | 403 this._filterString = value.toLowerCase(); |
| 551 this.refilter(); | 404 this.refilter(); |
| 552 }, | 405 }, |
| 553 | 406 |
| 554 filter: function(entry) | 407 filter: function(entry) |
| 555 { | 408 { |
| 556 if (this._ignoreEarlyReturns && entry.earlyReturn) | |
| 557 return false; | |
| 558 | |
| 559 if (this._filterString) | 409 if (this._filterString) |
| 560 { | 410 { |
| 561 let foundMatch = false; | 411 let foundMatch = false; |
| 562 for each (let label in entry.cols) | 412 for each (let label in entry.cols) |
| 563 if (label.toLowerCase().indexOf(this._filterString) >= 0) | 413 if (label.toLowerCase().indexOf(this._filterString) >= 0) |
| 564 foundMatch = true; | 414 foundMatch = true; |
| 565 | 415 |
| 566 if (!foundMatch) | 416 if (!foundMatch) |
| 567 return false; | 417 return false; |
| 568 } | 418 } |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 678 for (let i = 0; i < this.observers.length; i++) | 528 for (let i = 0; i < this.observers.length; i++) |
| 679 if (this.observers[i] == observer) | 529 if (this.observers[i] == observer) |
| 680 this.observers.splice(i--, 1); | 530 this.observers.splice(i--, 1); |
| 681 }, | 531 }, |
| 682 notifyObservers: function(operation, entry) | 532 notifyObservers: function(operation, entry) |
| 683 { | 533 { |
| 684 for each (let observer in this.observers) | 534 for each (let observer in this.observers) |
| 685 observer(this, operation, entry); | 535 observer(this, operation, entry); |
| 686 } | 536 } |
| 687 }; | 537 }; |
| OLD | NEW |