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