timeline events starting to work
diff --git a/weinre.web/demo/weinre-demo-pieces.html b/weinre.web/demo/weinre-demo-pieces.html
index c3ab90d..3d764a5 100644
--- a/weinre.web/demo/weinre-demo-pieces.html
+++ b/weinre.web/demo/weinre-demo-pieces.html
@@ -20,6 +20,8 @@
<script src="/weinre/common/Binding.transportd.js"></script>
<script src="/weinre/common/Callback.transportd.js"></script>
<script src="/weinre/common/EventListeners.transportd.js"></script>
+<script src="/weinre/common/Native.transportd.js"></script>
+<script src="/weinre/common/IDGenerator.transportd.js"></script>
<script src="/weinre/target/Console.transportd.js"></script>
<script src="/add-css-properties.js"></script>
<script src="/weinre/target/WiConsoleImpl.transportd.js"></script>
@@ -36,6 +38,7 @@
<script src="/weinre/target/Target.transportd.js"></script>
<script src="/weinre/target/ElementHighlighter.transportd.js"></script>
<script src="/weinre/target/InjectedScript.js"></script>
+<script src="/weinre/target/Timeline.transportd.js"></script>
<script src="/interfaces/all-json-idls.js"></script>
<script type="text/javascript">
@@ -43,6 +46,46 @@
require("weinre/target/Target").main()
</script>
+<script>
+var started = false
+var button
+
+function onLoad() {
+ if (!button) button = document.getElementById("button")
+
+ button.addEventListener("click", function() {
+ if (!started) {
+ button.value = "stop stuff"
+ startStuff()
+ }
+ else {
+ button.value = "start stuff"
+ stopStuff()
+ }
+ started = !started
+ })
+}
+
+var interval
+
+function startStuff() {
+ interval = setInterval(intervalStuff, 1000)
+}
+
+function stopStuff() {
+ clearInterval(interval)
+}
+
+function intervalStuff() {
+ setTimeout(function() { console.log("doing interval stuff")}, 333)
+
+ var xhr = new XMLHttpRequest()
+ xhr.open("GET", "../target/target-script.js", true)
+ xhr.send()
+}
+
+</script>
+
<style>
h1 {
color: green;
@@ -57,10 +100,16 @@
border: 0.2em solid;
padding: 3em;
}
+
+#button {
+ font-size: 150%;
+}
</style>
</head>
-<body>
+<body onload="onLoad()">
+<input id="button" type="button" value="start stuff">
+
<h1>this is a green h1 element</h1>
<h1 class="blue">this is a blue h1 element</h1>
<h1 style="color:red">this is a red h1 element</h1>
diff --git a/weinre.web/modules/weinre/client/Client.scoop b/weinre.web/modules/weinre/client/Client.scoop
index 9bebe40..8123edf 100644
--- a/weinre.web/modules/weinre/client/Client.scoop
+++ b/weinre.web/modules/weinre/client/Client.scoop
@@ -6,6 +6,8 @@
* Copyright (c) 2010, 2011 IBM Corporation
*/
+requireClass ../common/Native
+
requireClass ../common/IDLTools
requireClass ../common/Callback
requireClass ../common/Weinre
@@ -74,8 +76,8 @@
var toolButtonsToHide = ["scripts"]
toolButtonsToHide.forEach(function(toolButtonToHide){
- if (!WebInspector.panels[toolButtonToHide]) continue
- if (!WebInspector.panels[toolButtonToHide].toolbarItem) continue
+ if (!WebInspector.panels[toolButtonToHide]) return
+ if (!WebInspector.panels[toolButtonToHide].toolbarItem) return
WebInspector.panels[toolButtonToHide].toolbarItem.style.display = "none"
})
@@ -114,7 +116,7 @@
// use a delay, otherwise reloading will cause this stuff to flash
// before page is actually reloaded
- setTimeout(function() {
+ Native.setTimeout(function() {
WebInspector.panels.remote.connectionClosed()
WebInspector.currentPanel = WebInspector.panels.remote
}, 1000)
diff --git a/weinre.web/modules/weinre/client/InspectorBackendImpl.scoop b/weinre.web/modules/weinre/client/InspectorBackendImpl.scoop
index f4aeb73..a39ee09 100644
--- a/weinre.web/modules/weinre/client/InspectorBackendImpl.scoop
+++ b/weinre.web/modules/weinre/client/InspectorBackendImpl.scoop
@@ -65,7 +65,9 @@
//-----------------------------------------------------------------------------
method registerDomainDispatcher(name, intf)
this.registeredDomainDispatchers[name] = intf
-
+
//-----------------------------------------------------------------------------
method getRegisteredDomainDispatcher(name)
+ if (!this.registeredDomainDispatchers.hasOwnProperty(name)) return null
+
return this.registeredDomainDispatchers[name]
diff --git a/weinre.web/modules/weinre/client/InspectorFrontendHostImpl.scoop b/weinre.web/modules/weinre/client/InspectorFrontendHostImpl.scoop
index f0d0e17..b4514b6 100644
--- a/weinre.web/modules/weinre/client/InspectorFrontendHostImpl.scoop
+++ b/weinre.web/modules/weinre/client/InspectorFrontendHostImpl.scoop
@@ -23,7 +23,7 @@
//-----------------------------------------------------------------------------
method hiddenPanels
- return "audits,profiles,resources,timeline,network"
+ return "audits,profiles,resources,network"
// return "audits,profiles,resources,scripts,timeline,network"
//-----------------------------------------------------------------------------
diff --git a/weinre.web/modules/weinre/client/WeinreClientEventsImpl.scoop b/weinre.web/modules/weinre/client/WeinreClientEventsImpl.scoop
index 1dc8b3c..f84f61f 100644
--- a/weinre.web/modules/weinre/client/WeinreClientEventsImpl.scoop
+++ b/weinre.web/modules/weinre/client/WeinreClientEventsImpl.scoop
@@ -51,6 +51,9 @@
if (clientId != Weinre.clientId) return
Weinre.targetId = targetId
+
+ WebInspector.panels.elements.reset()
+ WebInspector.panels.timeline._clearPanel()
//-----------------------------------------------------------------------------
method connectionDestroyed(/*int*/ clientId, /*int*/ targetId)
diff --git a/weinre.web/modules/weinre/common/IDGenerator.scoop b/weinre.web/modules/weinre/common/IDGenerator.scoop
new file mode 100644
index 0000000..0b91770
--- /dev/null
+++ b/weinre.web/modules/weinre/common/IDGenerator.scoop
@@ -0,0 +1,20 @@
+
+/*
+ * weinre is available under *either* the terms of the modified BSD license *or* the
+ * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
+ *
+ * Copyright (c) 2011 IBM Corporation
+ */
+
+//-----------------------------------------------------------------------------
+class IDGenerator
+
+//-----------------------------------------------------------------------------
+init
+ var nextId = 1
+
+//-----------------------------------------------------------------------------
+static method next
+ var result = nextId
+ nextId += 1
+ return result
\ No newline at end of file
diff --git a/weinre.web/modules/weinre/common/MessageDispatcher.scoop b/weinre.web/modules/weinre/common/MessageDispatcher.scoop
index 038c43a..71b7b36 100644
--- a/weinre.web/modules/weinre/common/MessageDispatcher.scoop
+++ b/weinre.web/modules/weinre/common/MessageDispatcher.scoop
@@ -156,7 +156,8 @@
var methodSignature = intfName + "." + methodName + "()"
- var intf = this._interfaces[intfName]
+ var intf = this._interfaces.hasOwnProperty(intfName) && this._interfaces[intfName]
+
if (!intf && InspectorBackend && intfName.match(/.*Notify/)) {
intf = InspectorBackend.getRegisteredDomainDispatcher(intfName.substr(0,intfName.length-6))
}
diff --git a/weinre.web/modules/weinre/common/Native.scoop b/weinre.web/modules/weinre/common/Native.scoop
new file mode 100644
index 0000000..cc8ce08
--- /dev/null
+++ b/weinre.web/modules/weinre/common/Native.scoop
@@ -0,0 +1,29 @@
+
+/*
+ * weinre is available under *either* the terms of the modified BSD license *or* the
+ * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
+ *
+ * Copyright (c) 2011 IBM Corporation
+ */
+
+//-----------------------------------------------------------------------------
+class Native
+
+//-----------------------------------------------------------------------------
+init
+ Native.original = {}
+
+ Native.original.clearInterval = window.clearInterval
+ Native.original.clearTimeout = window.clearTimeout
+ Native.original.setTimeout = window.setTimeout
+ Native.original.setInterval = window.setInterval
+ Native.original.XMLHttpRequest = window.XMLHttpRequest
+ Native.original.XMLHttpRequest_open = window.XMLHttpRequest.prototype.open
+
+ Native.clearInterval = function() { return Native.original.clearInterval.apply( window, [].slice.call(arguments))}
+ Native.clearTimeout = function() { return Native.original.clearTimeout.apply( window, [].slice.call(arguments))}
+ Native.setInterval = function() { return Native.original.setInterval.apply( window, [].slice.call(arguments))}
+ Native.setTimeout = function() { return Native.original.setTimeout.apply( window, [].slice.call(arguments))}
+ Native.XMLHttpRequest = function() { return new Native.original.XMLHttpRequest()}
+ Native.XMLHttpRequest_open = function() { return Native.original.XMLHttpRequest_open.apply(this, [].slice.call(arguments))}
+
\ No newline at end of file
diff --git a/weinre.web/modules/weinre/common/WebSocketXhr.scoop b/weinre.web/modules/weinre/common/WebSocketXhr.scoop
index b270ffd..ce6b6c3 100644
--- a/weinre.web/modules/weinre/common/WebSocketXhr.scoop
+++ b/weinre.web/modules/weinre/common/WebSocketXhr.scoop
@@ -9,6 +9,7 @@
requireClass ./Ex
requireClass ./Weinre
requireClass ./EventListeners
+requireClass ./Native
//-----------------------------------------------------------------------------
class WebSocketXhr(url)
@@ -16,6 +17,8 @@
//-----------------------------------------------------------------------------
init
+ var XMLHttpRequest = Native.XMLHttpRequest
+
WebSocketXhr.CONNECTING = 0
WebSocketXhr.OPEN = 1
WebSocketXhr.CLOSING = 2
@@ -98,7 +101,7 @@
return
}
- window.setTimeout(function() {self._readLoop()}, 0)
+ Native.setTimeout(function() {self._readLoop()}, 0)
datum.forEach(function(data) {
self._fireEventListeners("message", {data: data})
@@ -133,7 +136,7 @@
if (xhr.status != 200) return this._handleXhrResponseError(xhr)
this._sendInProgress = false
- window.setTimeout(function() {httpSocket._sendQueued()}, 0)
+ Native.setTimeout(function() {httpSocket._sendQueued()}, 0)
//-----------------------------------------------------------------------------
method close
diff --git a/weinre.web/modules/weinre/target/Console.scoop b/weinre.web/modules/weinre/target/Console.scoop
index 54e85ae..ca94ad9 100644
--- a/weinre.web/modules/weinre/target/Console.scoop
+++ b/weinre.web/modules/weinre/target/Console.scoop
@@ -7,6 +7,7 @@
*/
requireClass ../common/Weinre
+requireClass ../target/Timeline
//-----------------------------------------------------------------------------
class Console
@@ -121,8 +122,8 @@
Weinre.notImplemented(arguments.callee.signature)
//-----------------------------------------------------------------------------
-method markTimeline
- Weinre.notImplemented(arguments.callee.signature)
+method markTimeline(message)
+ Timeline.addRecord_Mark(message)
//-----------------------------------------------------------------------------
method lastWMLErrorMessage
diff --git a/weinre.web/modules/weinre/target/Target.scoop b/weinre.web/modules/weinre/target/Target.scoop
index 9109f1f..8aede78 100644
--- a/weinre.web/modules/weinre/target/Target.scoop
+++ b/weinre.web/modules/weinre/target/Target.scoop
@@ -6,6 +6,8 @@
* Copyright (c) 2010, 2011 IBM Corporation
*/
+requireClass ../common/Native
+
requireClass ../common/Ex
requireClass ../common/Binding
requireClass ../common/Callback
diff --git a/weinre.web/modules/weinre/target/Timeline.scoop b/weinre.web/modules/weinre/target/Timeline.scoop
new file mode 100644
index 0000000..0d59b7a
--- /dev/null
+++ b/weinre.web/modules/weinre/target/Timeline.scoop
@@ -0,0 +1,257 @@
+
+/*
+ * weinre is available under *either* the terms of the modified BSD license *or* the
+ * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
+ *
+ * Copyright (c) 2011 IBM Corporation
+ */
+
+requireClass ../common/Ex
+requireClass ../common/Weinre
+
+requireClass ../common/Native
+
+//-----------------------------------------------------------------------------
+class Timeline
+
+//-----------------------------------------------------------------------------
+static method start
+ Running = true
+
+//-----------------------------------------------------------------------------
+static method stop
+ Running = false
+
+//-----------------------------------------------------------------------------
+static method isRunning
+ return Running
+
+//-----------------------------------------------------------------------------
+static method addRecord_Mark(message)
+ if (!Timeline.isRunning()) return
+
+ var record = {}
+
+ record.type = TimelineRecordType.Mark
+ record.category = { name: "scripting" }
+ record.startTime = Date.now()
+ record.data = { message: message }
+
+ Weinre.wi.TimelineNotify.addRecordToTimeline(record)
+
+//-----------------------------------------------------------------------------
+static method addRecord_EventDispatch(event, name, category)
+ if (!Timeline.isRunning()) return
+
+ if (!category) category = "scripting"
+ var record = {}
+
+ record.type = TimelineRecordType.EventDispatch
+ record.category = { name: category }
+ record.startTime = Date.now()
+ record.data = { type: event.type }
+
+ Weinre.wi.TimelineNotify.addRecordToTimeline(record)
+
+//-----------------------------------------------------------------------------
+static method addRecord_TimerInstall(id, timeout, singleShot)
+ if (!Timeline.isRunning()) return
+
+ var record = {}
+
+ record.type = TimelineRecordType.TimerInstall
+ record.category = { name: "scripting" }
+ record.startTime = Date.now()
+ record.data = { timerId: id, timeout: timeout, singleShot: singleShot }
+
+ Weinre.wi.TimelineNotify.addRecordToTimeline(record)
+
+//-----------------------------------------------------------------------------
+static method addRecord_TimerRemove(id, timeout, singleShot)
+ if (!Timeline.isRunning()) return
+
+ var record = {}
+
+ record.type = TimelineRecordType.TimerRemove
+ record.category = { name: "scripting" }
+ record.startTime = Date.now()
+ record.data = { timerId: id, timeout: timeout, singleShot: singleShot }
+
+ Weinre.wi.TimelineNotify.addRecordToTimeline(record)
+
+//-----------------------------------------------------------------------------
+static method addRecord_XHRReadyStateChange(url, readyState)
+ if (!Timeline.isRunning()) return
+
+ var record = {}
+
+ record.type = TimelineRecordType.XHRReadyStateChange
+ record.category = { name: "scripting" }
+ record.startTime = Date.now()
+ record.data = { url: url, readyState: readyState }
+
+ Weinre.wi.TimelineNotify.addRecordToTimeline(record)
+
+//-----------------------------------------------------------------------------
+static method addRecord_TimerFire(id, timeout, singleShot)
+
+//-----------------------------------------------------------------------------
+static method installGlobalListeners
+ if (applicationCache) {
+ applicationCache.addEventListener("checking", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.checking", "loading")}, false)
+ applicationCache.addEventListener("error", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.error", "loading")}, false)
+ applicationCache.addEventListener("noupdate", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.noupdate", "loading")}, false)
+ applicationCache.addEventListener("downloading", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.downloading", "loading")}, false)
+ applicationCache.addEventListener("progress", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.progress", "loading")}, false)
+ applicationCache.addEventListener("updateready", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.updateready", "loading")}, false)
+ applicationCache.addEventListener("cached", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.cached", "loading")}, false)
+ applicationCache.addEventListener("obsolete", function(e) {Timeline.addRecord_EventDispatch(e, "applicationCache.obsolete", "loading")}, false)
+ }
+
+ // window.addEventListener("deviceorientation", function(e) {Timeline.addRecord_EventDispatch("window.deviceorientation")}, false)
+ window.addEventListener("error", function(e) {Timeline.addRecord_EventDispatch(e, "window.error")}, false)
+ window.addEventListener("hashchange", function(e) {Timeline.addRecord_EventDispatch(e, "window.hashchange")}, false)
+ window.addEventListener("message", function(e) {Timeline.addRecord_EventDispatch(e, "window.message")}, false)
+ window.addEventListener("offline", function(e) {Timeline.addRecord_EventDispatch(e, "window.offline")}, false)
+ window.addEventListener("online", function(e) {Timeline.addRecord_EventDispatch(e, "window.online")}, false)
+ window.addEventListener("scroll", function(e) {Timeline.addRecord_EventDispatch(e, "window.scroll")}, false)
+
+//-----------------------------------------------------------------------------
+static method installFunctionWrappers
+ window.clearInterval = wrapped_clearInterval
+ window.clearTimeout = wrapped_clearTimeout
+ window.setTimeout = wrapped_setTimeout
+ window.setInterval = wrapped_setInterval
+
+ window.XMLHttpRequest.prototype.open = wrapped_XMLHttpRequest_open
+ window.XMLHttpRequest = wrapped_XMLHttpRequest
+
+
+//-----------------------------------------------------------------------------
+function wrapped_setInterval(code, interval)
+ var code = instrumentedTimerCode(code, interval, false)
+ var id = Native.setInterval(code, interval)
+
+ code.__timerId = id
+
+ addTimer(id, interval, false)
+
+ return id
+
+//-----------------------------------------------------------------------------
+function wrapped_setTimeout(code, delay)
+ var code = instrumentedTimerCode(code, delay, true)
+ var id = Native.setTimeout(code, delay)
+
+ code.__timerId = id
+
+ addTimer(id, delay, true)
+
+ return id
+
+//-----------------------------------------------------------------------------
+function wrapped_clearInterval(id)
+ var result = Native.clearInterval(id)
+
+ removeTimer(id, false)
+ return result
+
+//-----------------------------------------------------------------------------
+function wrapped_clearTimeout(id)
+ var result = Native.clearTimeout(id)
+
+ removeTimer(id, true)
+ return result
+
+//-----------------------------------------------------------------------------
+function addTimer(id, timeout, singleShot)
+ var timerSet = singleShot ? TimerTimeouts : TimerIntervals
+
+ timerSet[id] = {
+ id: id,
+ timeout: timeout,
+ singleShot: singleShot
+ }
+
+ Timeline.addRecord_TimerInstall(id, timeout, singleShot)
+
+//-----------------------------------------------------------------------------
+function removeTimer(id, singleShot)
+ var timerSet = singleShot ? TimerTimeouts : TimerIntervals
+ var timer = timerSet[id]
+
+ if (!timer) return
+
+ Timeline.addRecord_TimerRemove(id, timer.timeout, singleShot)
+
+ delete timerSet[id]
+
+//-----------------------------------------------------------------------------
+function instrumentedTimerCode(code, timeout, singleShot)
+ if (typeof(code) != "function") return code
+
+ var instrumentedCode = function() {
+ var result = code()
+ var id = arguments.callee.__timerId
+
+ Timeline.addRecord_TimerFire(id, timeout, singleShot)
+
+ return result
+ }
+
+ return instrumentedCode
+
+//-----------------------------------------------------------------------------
+function wrapped_XMLHttpRequest
+ var xhr = new Native.XMLHttpRequest()
+ xhr.addEventListener("readystatechange", getXhrEventHandler(xhr), false)
+ return xhr
+
+//-----------------------------------------------------------------------------
+function wrapped_XMLHttpRequest_open()
+ var xhr = this
+ var result = Native.XMLHttpRequest_open.apply(xhr, [].slice.call(arguments))
+ xhr.__weinre_url = arguments[1]
+ return result
+
+
+//-----------------------------------------------------------------------------
+function getXhrEventHandler(xhr)
+ return function(event) {
+ Timeline.addRecord_XHRReadyStateChange(xhr.__weinre_url, xhr.readyState)
+ }
+
+//-----------------------------------------------------------------------------
+init
+ var Running = false
+
+ var TimerTimeouts = {}
+ var TimerIntervals = {}
+
+ var TimelineRecordType = {
+ EventDispatch: 0,
+ Layout: 1,
+ RecalculateStyles: 2,
+ Paint: 3,
+ ParseHTML: 4,
+ TimerInstall: 5,
+ TimerRemove: 6,
+ TimerFire: 7,
+ XHRReadyStateChange: 8,
+ XHRLoad: 9,
+ EvaluateScript: 10,
+ Mark: 11,
+ ResourceSendRequest: 12,
+ ResourceReceiveResponse: 13,
+ ResourceFinish: 14,
+ FunctionCall: 15,
+ ReceiveResourceData: 16,
+ GCEvent: 17,
+ MarkDOMContent: 18,
+ MarkLoad: 19,
+ ScheduleResourceRequest: 20
+ }
+
+ Timeline.installGlobalListeners()
+ Timeline.installFunctionWrappers()
+
\ No newline at end of file
diff --git a/weinre.web/modules/weinre/target/WiInspectorImpl.scoop b/weinre.web/modules/weinre/target/WiInspectorImpl.scoop
index 26bdab9..098e58b 100644
--- a/weinre.web/modules/weinre/target/WiInspectorImpl.scoop
+++ b/weinre.web/modules/weinre/target/WiInspectorImpl.scoop
@@ -7,6 +7,7 @@
*/
requireClass ../common/Weinre
+requireClass ../target/Timeline
//-----------------------------------------------------------------------------
class WiInspectorImpl
@@ -41,3 +42,24 @@
Weinre.WeinreTargetCommands.sendClientCallback(callback)
}
+//-----------------------------------------------------------------------------
+method startTimelineProfiler(callback)
+ Timeline.start()
+
+ Weinre.wi.TimelineNotify.timelineProfilerWasStarted()
+
+ if (callback) {
+ Weinre.WeinreTargetCommands.sendClientCallback(callback)
+ }
+
+
+//-----------------------------------------------------------------------------
+method stopTimelineProfiler(callback)
+ Timeline.stop()
+
+ Weinre.wi.TimelineNotify.timelineProfilerWasStopped()
+
+ if (callback) {
+ Weinre.WeinreTargetCommands.sendClientCallback(callback)
+ }
+