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