WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
28908
Support conditional breakpoints in the frontend
https://bugs.webkit.org/show_bug.cgi?id=28908
Summary
Support conditional breakpoints in the frontend
Alexander Pavlov (apavlov)
Reported
2009-09-02 06:14:55 PDT
This bug is to track the conditional breakpoints implementation in the Web Inspector frontend. The parent bug for conditional breakpoints is
https://bugs.webkit.org/show_bug.cgi?id=21449
Attachments
patch
(72.40 KB, patch)
2009-09-03 08:40 PDT
,
Alexander Pavlov (apavlov)
timothy
: review-
Details
Formatted Diff
Diff
Popup layout inside source frame
(45.42 KB, image/png)
2009-09-11 05:36 PDT
,
Alexander Pavlov (apavlov)
no flags
Details
patch (fixed)
(71.94 KB, patch)
2009-09-14 08:27 PDT
,
Alexander Pavlov (apavlov)
timothy
: review-
Details
Formatted Diff
Diff
patch (fixed v2)
(67.34 KB, patch)
2009-09-14 11:45 PDT
,
Alexander Pavlov (apavlov)
timothy
: review+
Details
Formatted Diff
Diff
Show Obsolete
(2)
View All
Add attachment
proposed patch, testcase, etc.
Alexander Pavlov (apavlov)
Comment 1
2009-09-03 08:40:13 PDT
Created
attachment 38993
[details]
patch This patch uses a workaround for
https://bugs.webkit.org/show_bug.cgi?id=28913
(alternative popup parenting/layout)
Timothy Hatcher
Comment 2
2009-09-07 07:52:26 PDT
Can you attach a screenshot of the new layout?
Alexander Pavlov (apavlov)
Comment 3
2009-09-11 05:36:23 PDT
Created
attachment 39422
[details]
Popup layout inside source frame The new layout is only slightly different from the original one: the popup is bound by the source frame rather than the entire WebInspector window.
Timothy Hatcher
Comment 4
2009-09-11 11:51:09 PDT
Comment on
attachment 38993
[details]
patch
> + this._document = element ? element.ownerDocument : undefined; > + this._contentElement = element; > + this._glasspaneElement = undefined; > + this._keyHandler = this._keyEventHandler.bind(this); > + this._mouseDownHandler = this._mouseDownEventHandler.bind(this); > + this._anchorElement = undefined; > + this._visible = false; > + this._autoHide = true; > + this._position = {x: 0, y: 0};
You don't need to explicitly set things to undefined. They will be undefined by default. Either use null or remove them. I don't think you should keep a reference to the document either, just ask the element when you need it.
> + var doc = this._document; > + if (!doc) > + return;
Don't abbrivate doc, "ownerDocument" would be best.
> + this._setDisplayed(this._contentElement, false); > + doc.body.appendChild(this._contentElement); > + this._contentElement.style.visibility = "hidden"; > + this._contentElement.positionAt(0, 0); > + this._setDisplayed(this._contentElement, true); > + this.positionElement(); > + this._contentElement.style.visibility = "visible";
Why do you do this hidden then visible dance? Nothing is rendered until JavaScript finishes execution, so you just need to make it visible. You shouldn't need any of the _setDisplayed or _contentElement.style.visibility lines. Also, if you do need to toggle visibility, that should be done with a style class not a direct manipulation of the style. Only variable things like position should be set on the style.
> + this._contentElement.style.visibility = "hidden"; > + this._setDisplayed(this._contentElement, false);
This should be doen with a style class. Also why do you need to toggle both display: none and visibility: hidden? Just doing display: none on the top most element is sufficient. (Again do that with a style class change. You can use our existing "hidden" class for that.)
> + this._document = x ? x.ownerDocument : undefined;
Don't reference the document. Just use the this._contentElement.ownerDocument when you need the document. (Which you already do in _positionAtAnchor.)
> + positionElement: function() > + { > + this._positionAtAnchor(); > + },
You should just put the implementation of _positionAtAnchor in positionElement, since it is only called from here.
> + var anchorPos = {x: anchorElement.totalOffsetLeft, y: anchorElement.totalOffsetTop}; > + anchorPos = this._pointToFrame(anchorPos, anchorElement.ownerDocument, element.ownerDocument); > + var anchorBox = {x: anchorPos.x, y: anchorPos.y, width: anchorElement.offsetWidth, height: anchorElement.offsetHeight}; > + var elementBox = {x: element.totalOffsetLeft, y: element.totalOffsetTop, width: element.offsetWidth, height: element.offsetHeight}; > + var newElementPos = {x: 0, y: 0};
Don't abbrivate "pos".
> + _setDisplayed: function(element, isDisplayed) > + { > + element.style.display = isDisplayed ? "block" : "none"; > + },
You should be able to remove this based on my earlier comments.
> + _mouseDownEventHandler: function(event) > + { > + if (this._autoHide) { > + var popupBox = {x: this._contentElement.totalOffsetLeft, y: this._contentElement.totalOffsetTop, width: this._contentElement.offsetWidth, height: this._contentElement.offsetHeight}; > + if (!this._rectangleContains(popupBox, {x: event.clientX, y: event.clientY})) > + this.hide(); > + } > + },
You should be able to call hide() when event.originalTarget === this._glasspaneElement and remove all the bounding box stuff.
> + _pointToFrame: function(point, originalDoc, targetDoc) > + { > + var result = {x: point.x, y: point.y}; > + if (originalDoc != targetDoc) { > + var originalBody = originalDoc.body; > + var targetWindow = targetDoc.defaultView; > + var offset = originalBody.offsetRelativeToWindow(targetWindow); > + result.x += offset.x - originalBody.totalOffsetLeft; > + result.y += offset.y - originalBody.totalOffsetTop; > + } > + return result; > + },
Why do you need this? Isn't the popup in the same frame?
> + _rectangleContains: function(rect, point) > + { > + return point.x >= rect.x && point.x <= (rect.x + rect.height) && point.y >= rect.y && point.y <= (rect.y + rect.height); > + } > +}
Should be able to remove based on my earlier comment.
> + this._popup = undefined;
Undefined is the default, remove this.
> + if (event.button != 0 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) { > + return; > + }
No need for the braces, per our style guide.
> + var conditionElement = popupDoc.getElementById("bp-condition");
You should have another way to get this element. Using getElementById is fraggle.
> + var labelElement = document.createElement("div"); > + labelElement.className = "popup-message"; > + labelElement.style.margin = "0 0 2px 0"; > + labelElement.innerText = WebInspector.UIString("The breakpoint on line %d will stop only if this expression is true:", lineNumber); > + popupContentElement.appendChild(labelElement);
Consider using the <label> element. Also the margin should be in inspector.css, maybe with a enw class you use.
> +.breakpoint-list a.breakpoint-has-condition::after { > + content: " (?)"; > +}
What is this for?
> - this.innerText = oldText; > + if (this.tagName === "INPUT" && this.type === "text") > + this.value = oldText; > + else > + this.innerText = oldText;
This changed in TOT to use textContent instead of innerText. You will need to merge with that.
> +Element.prototype.offsetRelativeToWindow = function(targetWindow) > +{ > + var elementOffset = [0, 0]; > + var curElement = this; > + var curWindow = this.ownerDocument.defaultView; > + while (curWindow && curElement) { > + var pageOffset; > + if (curWindow === targetWindow) { > + pageOffset = [curElement.totalOffsetLeft, curElement.totalOffsetTop]; > + } else { > + var clientPos = curElement.getBoundingClientRect(); > + pageOffset = [clientPos.left, clientPos.top]; > + } > + elementOffset[0] += pageOffset[0]; > + elementOffset[1] += pageOffset[1]; > + > + if (!curWindow || curWindow === targetWindow) > + break; > + > + curElement = curWindow.frameElement; > + curWindow = curWindow.parent; > + } > + > + return elementOffset; > +}
I think you can simplify this by using offsetTop and offsetLeft and walk the offsetParent chain (like totalOffsetLeft). This should also return an object not an array. So {x: nn, y: nn}.
Alexander Pavlov (apavlov)
Comment 5
2009-09-14 08:27:19 PDT
Created
attachment 39545
[details]
patch (fixed) This patch version fixes the nits and enables condition editing for disabled breakpoints.
Alexander Pavlov (apavlov)
Comment 6
2009-09-14 08:30:52 PDT
(In reply to
comment #4
)
> (From update of
attachment 38993
[details]
) > > > + this._document = element ? element.ownerDocument : undefined; > > + this._contentElement = element; > > + this._glasspaneElement = undefined; > > + this._keyHandler = this._keyEventHandler.bind(this); > > + this._mouseDownHandler = this._mouseDownEventHandler.bind(this); > > + this._anchorElement = undefined; > > + this._visible = false; > > + this._autoHide = true; > > + this._position = {x: 0, y: 0}; > > You don't need to explicitly set things to undefined. They will be undefined by > default. Either use null or remove them. I don't think you should keep a
Sorry, I wrongfully assumed it was necessary to initialize fields with WebKit.
> reference to the document either, just ask the element when you need it.
Done.
> > + var doc = this._document; > > + if (!doc) > > + return; > > Don't abbrivate doc, "ownerDocument" would be best.
Done.
> > + this._setDisplayed(this._contentElement, false); > > + doc.body.appendChild(this._contentElement); > > + this._contentElement.style.visibility = "hidden"; > > + this._contentElement.positionAt(0, 0); > > + this._setDisplayed(this._contentElement, true); > > + this.positionElement(); > > + this._contentElement.style.visibility = "visible"; > > Why do you do this hidden then visible dance? Nothing is rendered until > JavaScript finishes execution, so you just need to make it visible. You
Thanks for the hint!
> shouldn't need any of the _setDisplayed or _contentElement.style.visibility > lines.
We might need the two that make the element visible, since the element could have been created with its visibility/display turned off. Added a JsDoc.
> Also, if you do need to toggle visibility, that should be done with a style > class not a direct manipulation of the style. Only variable things like > position should be set on the style. > > > + this._contentElement.style.visibility = "hidden"; > > + this._setDisplayed(this._contentElement, false); > > This should be doen with a style class. Also why do you need to toggle both > display: none and visibility: hidden? Just doing display: none on the top most > element is sufficient. (Again do that with a style class change. You can use > our existing "hidden" class for that.) > > > + this._document = x ? x.ownerDocument : undefined; > > Don't reference the document. Just use the this._contentElement.ownerDocument > when you need the document. (Which you already do in _positionAtAnchor.)
Done.
> > + positionElement: function() > > + { > > + this._positionAtAnchor(); > > + }, > > You should just put the implementation of _positionAtAnchor in positionElement, > since it is only called from here.
Done.
> > + var anchorPos = {x: anchorElement.totalOffsetLeft, y: anchorElement.totalOffsetTop}; > > + anchorPos = this._pointToFrame(anchorPos, anchorElement.ownerDocument, element.ownerDocument); > > + var anchorBox = {x: anchorPos.x, y: anchorPos.y, width: anchorElement.offsetWidth, height: anchorElement.offsetHeight}; > > + var elementBox = {x: element.totalOffsetLeft, y: element.totalOffsetTop, width: element.offsetWidth, height: element.offsetHeight}; > > + var newElementPos = {x: 0, y: 0}; > > Don't abbrivate "pos".
Done.
> > + _setDisplayed: function(element, isDisplayed) > > + { > > + element.style.display = isDisplayed ? "block" : "none"; > > + }, > > You should be able to remove this based on my earlier comments.
Done.
> > + _mouseDownEventHandler: function(event) > > + { > > + if (this._autoHide) { > > + var popupBox = {x: this._contentElement.totalOffsetLeft, y: this._contentElement.totalOffsetTop, width: this._contentElement.offsetWidth, height: this._contentElement.offsetHeight}; > > + if (!this._rectangleContains(popupBox, {x: event.clientX, y: event.clientY})) > > + this.hide(); > > + } > > + }, > > You should be able to call hide() when event.originalTarget === > this._glasspaneElement and remove all the bounding box stuff.
Correct, done.
> > + _pointToFrame: function(point, originalDoc, targetDoc) > > + { > > + var result = {x: point.x, y: point.y}; > > + if (originalDoc != targetDoc) { > > + var originalBody = originalDoc.body; > > + var targetWindow = targetDoc.defaultView; > > + var offset = originalBody.offsetRelativeToWindow(targetWindow); > > + result.x += offset.x - originalBody.totalOffsetLeft; > > + result.y += offset.y - originalBody.totalOffsetTop; > > + } > > + return result; > > + }, > > Why do you need this? Isn't the popup in the same frame?
It is, as long as a workaround for
https://bugs.webkit.org/show_bug.cgi?id=28913
is in place. I still hope to move the popup into the topmost frame when the bug is fixed. Removed for now.
> > + _rectangleContains: function(rect, point) > > + { > > + return point.x >= rect.x && point.x <= (rect.x + rect.height) && point.y >= rect.y && point.y <= (rect.y + rect.height); > > + } > > +} > Should be able to remove based on my earlier comment.
Done.
> > > + this._popup = undefined; > > Undefined is the default, remove this.
Done.
> > + if (event.button != 0 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) { > > + return; > > + } > No need for the braces, per our style guide.
Done.
> > + var conditionElement = popupDoc.getElementById("bp-condition"); > > You should have another way to get this element. Using getElementById is > fraggle.
Done.
> > > + var labelElement = document.createElement("div"); > > + labelElement.className = "popup-message"; > > + labelElement.style.margin = "0 0 2px 0"; > > + labelElement.innerText = WebInspector.UIString("The breakpoint on line %d will stop only if this expression is true:", lineNumber); > > + popupContentElement.appendChild(labelElement); > > Consider using the <label> element. Also the margin should be in inspector.css, > maybe with a enw class you use.
Done.
> > +.breakpoint-list a.breakpoint-has-condition::after { > > + content: " (?)"; > > +} > > What is this for?
This is to denote conditional breakpoints in the Breakpoints sidebar pane (a question mark after the breakpoint label). I can as well remove it if we don't want those to be displayed differently.
> > - this.innerText = oldText; > > + if (this.tagName === "INPUT" && this.type === "text") > > + this.value = oldText; > > + else > > + this.innerText = oldText; > > This changed in TOT to use textContent instead of innerText. You will need to > merge with that.
Thanks, merged.
> > +Element.prototype.offsetRelativeToWindow = function(targetWindow) > > +{ > > + var elementOffset = [0, 0]; > > + var curElement = this; > > + var curWindow = this.ownerDocument.defaultView; > > + while (curWindow && curElement) { > > + var pageOffset; > > + if (curWindow === targetWindow) { > > + pageOffset = [curElement.totalOffsetLeft, curElement.totalOffsetTop]; > > + } else { > > + var clientPos = curElement.getBoundingClientRect(); > > + pageOffset = [clientPos.left, clientPos.top]; > > + } > > + elementOffset[0] += pageOffset[0]; > > + elementOffset[1] += pageOffset[1]; > > + > > + if (!curWindow || curWindow === targetWindow) > > + break; > > + > > + curElement = curWindow.frameElement; > > + curWindow = curWindow.parent; > > + } > > + > > + return elementOffset; > > +} > > I think you can simplify this by using offsetTop and offsetLeft and walk the > offsetParent chain (like totalOffsetLeft). This should also return an object
Right, both "this" element and iframe hierarchies...
> not an array. So {x: nn, y: nn}.
Done.
Timothy Hatcher
Comment 7
2009-09-14 09:52:23 PDT
Comment on
attachment 39545
[details]
patch (fixed)
> +WebInspector.Popup.prototype = > +{
The brace for prototypes should be next to the equals on one line to match the other classes.
> + var popupDoc = this.element.contentDocument;
We don't abbreviate Document as Doc in WebKit. This should be popupDocument.
> +.breakpoint-list a.breakpoint-has-condition::after { > + content: " (?)"; > +}
I now see what this is for. I don't think this is the best way to show conditional break points. I think we should show the condition somehow in the Breakpoints pane. (This also isn't localizable in CSS.) Remove this for now and file a bug about showing them in the Breakpoints pane.
Alexander Pavlov (apavlov)
Comment 8
2009-09-14 11:45:26 PDT
Created
attachment 39562
[details]
patch (fixed v2) Fixed remaining 3 nits
Alexander Pavlov (apavlov)
Comment 9
2009-09-14 12:27:42 PDT
(In reply to
comment #7
)
> (From update of
attachment 39545
[details]
) > > +WebInspector.Popup.prototype = > > +{ > > The brace for prototypes should be next to the equals on one line to match the > other classes.
Sorry, I confused them a bit.
> > + var popupDoc = this.element.contentDocument; > > We don't abbreviate Document as Doc in WebKit. This should be popupDocument.
Oops, fixed.
> > +.breakpoint-list a.breakpoint-has-condition::after { > > + content: " (?)"; > > +} > > I now see what this is for. I don't think this is the best way to show > conditional break points. I think we should show the condition somehow in the > Breakpoints pane. (This also isn't localizable in CSS.)
Yes, L10N was one of my concerns about this solution, too. I considered several approaches, but no consistent decision yet.
> Remove this for now and file a bug about showing them in the Breakpoints pane.
Filed
https://bugs.webkit.org/show_bug.cgi?id=29251
- let's discuss it there.
Anthony Ricaud
Comment 10
2009-09-15 06:16:48 PDT
Landed in 48392
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug