Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 /** | |
| 6 * @typedef {{type: string, useCapture: boolean, handler: function()}} | |
| 7 */ | |
| 8 WebInspector.PageEventListener; | |
|
pfeldman
2015/09/03 18:56:35
Still don't get which is what.
kozy
2015/09/03 22:17:25
Renamed to WebInspector.EventListenerObjectInInspe
| |
| 9 | |
| 10 /** | |
| 11 * @typedef {{type:string, useCapture:boolean, handler:!WebInspector.RemoteObjec t, location:!WebInspector.DebuggerModel.Location}} | |
| 12 */ | |
| 13 WebInspector.EventListenerData; | |
| 14 | |
| 15 /** | |
| 16 * @typedef {{eventListeners:!Array<!{type:string, handler:function(), useCaptur e:boolean}>, internalHandlers:?Array<function()>}} | |
| 17 */ | |
| 18 WebInspector.EventListenerRawResult; | |
|
pfeldman
2015/09/03 20:22:45
This should be entirely encapsulated into the func
kozy
2015/09/03 22:17:25
It looks like I can't encapsulate typedef: https:/
| |
| 19 | |
| 20 /** | |
| 21 * @typedef {{eventListeners:!Array<!WebInspector.EventListener>, internalHandle rs:?WebInspector.RemoteArray}} | |
| 22 */ | |
| 23 WebInspector.PageEventListenersResult; | |
| 24 | |
| 25 /** | |
| 26 * @param {!WebInspector.RemoteObject} object | |
| 27 * @return {!Promise<!WebInspector.PageEventListenersResult>} | |
| 28 */ | |
| 29 WebInspector.EventListener.frameworkEventListeners = function(object) | |
| 30 { | |
| 31 var listenersResult = /** @type {!WebInspector.PageEventListenersResult} */( {eventListeners: []}); | |
| 32 return object.callFunctionPromise(frameworkEventListeners, undefined) | |
| 33 .then(assertCallFunctionResult) | |
| 34 .then(getOwnProperties) | |
| 35 .then(createEventListeners) | |
| 36 .then(returnResult) | |
| 37 .catchException(listenersResult); | |
| 38 | |
| 39 /** | |
| 40 * @param {!WebInspector.RemoteObject} object | |
| 41 * @return {!Promise<!{properties: ?Array.<!WebInspector.RemoteObjectPropert y>, internalProperties: ?Array.<!WebInspector.RemoteObjectProperty>}>} | |
| 42 */ | |
| 43 function getOwnProperties(object) | |
| 44 { | |
| 45 return object.getOwnPropertiesPromise(); | |
| 46 } | |
| 47 | |
| 48 /** | |
| 49 * @param {!{properties: ?Array<!WebInspector.RemoteObjectProperty>, interna lProperties: ?Array<!WebInspector.RemoteObjectProperty>}} result | |
| 50 * @return {!Promise<undefined>} | |
| 51 */ | |
| 52 function createEventListeners(result) | |
| 53 { | |
| 54 if (!result.properties) | |
| 55 throw new Error("Object properties is empty"); | |
| 56 var promises = []; | |
| 57 for (var property of result.properties) { | |
| 58 if (property.name === "eventListeners" && property.value) | |
| 59 promises.push(convertToEventListeners(property.value).then(store EventListeners)); | |
| 60 if (property.name === "internalHandlers" && property.value) | |
| 61 promises.push(convertToInternalHandlers(property.value).then(sto reInternalHandlers)); | |
| 62 } | |
| 63 return /** @type {!Promise<undefined>} */(Promise.all(promises)); | |
| 64 } | |
| 65 | |
| 66 /** | |
| 67 * @param {!WebInspector.RemoteObject} pageEventListenersObject | |
| 68 * @return {!Promise<!Array<!WebInspector.EventListener>>} | |
| 69 */ | |
| 70 function convertToEventListeners(pageEventListenersObject) | |
| 71 { | |
| 72 return WebInspector.RemoteArray.objectAsArray(pageEventListenersObject) | |
| 73 .map(toEventListener) | |
| 74 .then(filterOutEmptyObjects); | |
| 75 | |
| 76 /** | |
| 77 * @param {!WebInspector.RemoteObject} listenerObject | |
| 78 * @return {!Promise<?WebInspector.EventListener>} | |
| 79 */ | |
| 80 function toEventListener(listenerObject) | |
| 81 { | |
| 82 var eventListenerData = /** @type {!WebInspector.EventListenerData} */({}); | |
| 83 var promises = []; | |
| 84 | |
| 85 promises.push(listenerObject.callFunctionJSONPromise(truncatePageEve ntListener, undefined).then(storeTrunkatedListener)); | |
| 86 | |
| 87 /** | |
| 88 * @suppressReceiverCheck | |
| 89 * @this {WebInspector.PageEventListener} | |
| 90 * @return {!{type:string, useCapture:boolean}} | |
| 91 */ | |
| 92 function truncatePageEventListener() | |
| 93 { | |
| 94 return {type: this.type, useCapture: this.useCapture}; | |
| 95 } | |
| 96 | |
| 97 /** | |
| 98 * @param {!{type:string, useCapture: boolean}} truncatedListener | |
| 99 * @return {undefined} | |
|
pfeldman
2015/09/03 18:56:35
return {undefined}?
kozy
2015/09/03 22:17:25
Removed.
| |
| 100 */ | |
| 101 function storeTrunkatedListener(truncatedListener) | |
| 102 { | |
| 103 eventListenerData.type = truncatedListener.type; | |
| 104 eventListenerData.useCapture = truncatedListener.useCapture; | |
| 105 return undefined; | |
| 106 } | |
| 107 | |
| 108 promises.push(listenerObject.callFunctionPromise(handlerFunction).th en(assertCallFunctionResult) | |
|
pfeldman
2015/09/03 18:56:35
stack them?
kozy
2015/09/03 22:17:25
Done.
| |
| 109 .then(toTargetFunction) | |
| 110 .then(storeFunctionWithDetails)); | |
| 111 | |
| 112 /** | |
| 113 * @suppressReceiverCheck | |
| 114 * @return {function()} | |
| 115 * @this {WebInspector.PageEventListener} | |
| 116 */ | |
| 117 function handlerFunction() | |
| 118 { | |
| 119 return this.handler; | |
| 120 } | |
| 121 | |
| 122 /** | |
| 123 * @param {!WebInspector.RemoteObject} functionObject | |
| 124 * @return {!Promise<undefined>} | |
| 125 */ | |
| 126 function storeFunctionWithDetails(functionObject) | |
| 127 { | |
| 128 eventListenerData.handler = functionObject; | |
| 129 return /** @type {!Promise<undefined>} */(functionObject.functio nDetailsPromise().then(storeFunctionDetails)); | |
| 130 } | |
| 131 | |
| 132 /** | |
| 133 * @param {?WebInspector.DebuggerModel.FunctionDetails} functionDeta ils | |
| 134 */ | |
| 135 function storeFunctionDetails(functionDetails) | |
| 136 { | |
| 137 if (!functionDetails || !functionDetails.location) | |
| 138 throw new Error("Empty function details or function details location"); | |
| 139 eventListenerData.location = functionDetails.location; | |
| 140 } | |
| 141 | |
| 142 return Promise.all(promises).then(createEventListener).catchExceptio n(/** @type {?WebInspector.EventListener} */(null)); | |
| 143 | |
| 144 /** | |
| 145 * @return {!WebInspector.EventListener} | |
| 146 */ | |
| 147 function createEventListener() | |
| 148 { | |
| 149 return new WebInspector.EventListener(eventListenerData.handler. _target, | |
|
pfeldman
2015/09/03 18:56:35
So you did not need this object, you could have us
kozy
2015/09/03 22:17:25
Done.
| |
| 150 eventListenerData.type, | |
| 151 eventListenerData.useCaptu re, | |
| 152 eventListenerData.handler, | |
| 153 eventListenerData.location , | |
| 154 "frameworkUser"); | |
| 155 } | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 /** | |
| 160 * @param {!WebInspector.RemoteObject} pageInternalHandlersObject | |
| 161 * @return {!Promise<!WebInspector.RemoteArray>} | |
| 162 */ | |
| 163 function convertToInternalHandlers(pageInternalHandlersObject) | |
| 164 { | |
| 165 return WebInspector.RemoteArray.objectAsArray(pageInternalHandlersObject ).map(toTargetFunction) | |
| 166 .then(WebInspector.RemoteArray.createFrom RemoteObjects); | |
| 167 } | |
| 168 | |
| 169 /** | |
| 170 * @param {!WebInspector.RemoteObject} functionObject | |
| 171 * @return {!Promise<!WebInspector.RemoteObject>} | |
| 172 */ | |
| 173 function toTargetFunction(functionObject) | |
| 174 { | |
| 175 return WebInspector.RemoteFunction.objectAsFunction(functionObject).targ etFunction(); | |
| 176 } | |
| 177 | |
| 178 /** | |
| 179 * @param {!Array<!WebInspector.EventListener>} eventListeners | |
| 180 */ | |
| 181 function storeEventListeners(eventListeners) | |
| 182 { | |
| 183 listenersResult.eventListeners = eventListeners; | |
| 184 } | |
| 185 | |
| 186 /** | |
| 187 * @param {!WebInspector.RemoteArray} internalHandlers | |
| 188 */ | |
| 189 function storeInternalHandlers(internalHandlers) | |
| 190 { | |
| 191 listenersResult.internalHandlers = internalHandlers; | |
| 192 } | |
| 193 | |
| 194 /** | |
| 195 * @return {!WebInspector.PageEventListenersResult} | |
| 196 */ | |
| 197 function returnResult() | |
| 198 { | |
| 199 return listenersResult; | |
| 200 } | |
| 201 | |
| 202 /** | |
| 203 * @param {!WebInspector.CallFunctionResult} result | |
| 204 * @return {!WebInspector.RemoteObject} | |
| 205 */ | |
| 206 function assertCallFunctionResult(result) | |
| 207 { | |
| 208 if (result.wasThrown || !result.object) | |
| 209 throw new Error("Exception in callFunction or empty result"); | |
| 210 return result.object; | |
| 211 } | |
| 212 | |
| 213 /** | |
| 214 * @param {!Array<?T>} objects | |
| 215 * @return {!Array<!T>} | |
| 216 * @template T | |
| 217 */ | |
| 218 function filterOutEmptyObjects(objects) | |
| 219 { | |
| 220 return objects.filter(filterOutEmpty); | |
| 221 | |
| 222 /** | |
| 223 * @param {?T} object | |
| 224 * @return {boolean} | |
| 225 * @template T | |
| 226 */ | |
| 227 function filterOutEmpty(object) | |
| 228 { | |
| 229 return !!object; | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 /* | |
| 234 frameworkEventListeners fetcher functions should produce following output: | |
| 235 { | |
| 236 // framework event listeners | |
| 237 "eventListeners": [ | |
| 238 { | |
| 239 "handler": function(), | |
| 240 "useCapture": true, | |
| 241 "type": "change" | |
| 242 }, | |
| 243 ... | |
| 244 ], | |
| 245 // internal framework event handlers | |
| 246 "internalHandlers": [ | |
| 247 function(), | |
| 248 function(), | |
| 249 ... | |
| 250 ] | |
| 251 } | |
| 252 */ | |
| 253 /** | |
| 254 * @suppressReceiverCheck | |
| 255 * @return {!WebInspector.EventListenerRawResult} | |
| 256 * @this {Object} | |
| 257 */ | |
| 258 function frameworkEventListeners() | |
| 259 { | |
| 260 var eventListeners = []; | |
| 261 var internalHandlers = []; | |
| 262 var fetchers = [jQueryFetcher]; | |
| 263 try { | |
| 264 if (self.devtoolsPageEventListeners && isArrayLike(self.devtoolsPage EventListeners)) | |
| 265 fetchers = fetchers.concat(self.devtoolsPageEventListeners); | |
| 266 } catch (e) { | |
| 267 } | |
| 268 | |
| 269 for (var i = 0; i < fetchers.length; ++i) { | |
| 270 try { | |
| 271 var fetcherResult = fetchers[i](this); | |
| 272 eventListeners = eventListeners.concat(fetcherResult.eventListen ers); | |
| 273 if (fetcherResult.internalHandlers) | |
| 274 internalHandlers = internalHandlers.concat(fetcherResult.int ernalHandlers); | |
| 275 } catch (e) { | |
| 276 } | |
| 277 } | |
| 278 var result = {eventListeners: eventListeners}; | |
| 279 if (internalHandlers.length) | |
| 280 result.internalHandlers = internalHandlers; | |
| 281 return result; | |
| 282 | |
| 283 /** | |
| 284 * @param {?Object} obj | |
| 285 * @return {boolean} | |
| 286 */ | |
| 287 function isArrayLike(obj) | |
| 288 { | |
| 289 if (!obj || typeof obj !== "object") | |
| 290 return false; | |
| 291 try { | |
| 292 if (typeof obj.splice === "function") { | |
| 293 var len = obj.length; | |
| 294 return typeof len === "number" && (len >>> 0 === len && (len > 0 || 1 / len > 0)); | |
| 295 } | |
| 296 } catch (e) { | |
| 297 } | |
| 298 return false; | |
| 299 } | |
| 300 | |
| 301 function jQueryFetcher(node) | |
| 302 { | |
| 303 if (!node || !(node instanceof Node)) | |
| 304 return {eventListeners: []}; | |
| 305 var jQuery = /** @type {?{fn,data,_data}}*/(window["jQuery"]); | |
| 306 if (!jQuery || !jQuery.fn) | |
| 307 return {eventListeners: []}; | |
| 308 var jQueryFunction = /** @type {function(!Node)} */(jQuery); | |
| 309 var data = jQuery._data || jQuery.data; | |
| 310 | |
| 311 var eventListeners = []; | |
| 312 var internalHandlers = []; | |
| 313 | |
| 314 if (typeof data === "function") { | |
| 315 var events = data(node, "events"); | |
| 316 for (var type in events) { | |
| 317 for (var key in events[type]) { | |
| 318 var frameworkListener = events[type][key]; | |
| 319 if (typeof frameworkListener === "object" || typeof fram eworkListener === "function") { | |
| 320 var listener = { | |
| 321 handler: frameworkListener.handler || frameworkL istener, | |
| 322 useCapture: true, | |
| 323 type: type | |
| 324 }; | |
| 325 eventListeners.push(listener); | |
| 326 } | |
| 327 } | |
| 328 } | |
| 329 var nodeData = data(node); | |
| 330 if (typeof nodeData.handle === "function") | |
| 331 internalHandlers.push(nodeData.handle); | |
| 332 } | |
| 333 var entry = jQueryFunction(node)[0]; | |
| 334 if (entry) { | |
| 335 var entryEvents = entry["$events"]; | |
| 336 for (var type in entryEvents) { | |
| 337 var events = entryEvents[type]; | |
| 338 for (var key in events) { | |
| 339 if (typeof events[key] === "function") { | |
| 340 var listener = { | |
| 341 handler: events[key], | |
| 342 useCapture: true, | |
| 343 type: type | |
| 344 }; | |
| 345 eventListeners.push(listener); | |
| 346 } | |
| 347 } | |
| 348 } | |
| 349 if (entry && entry["$handle"]) | |
| 350 internalHandlers.push(entry["$handle"]); | |
| 351 } | |
| 352 return {eventListeners: eventListeners, internalHandlers: internalHa ndlers}; | |
| 353 } | |
| 354 } | |
| 355 } | |
| OLD | NEW |