Autopsy Of A Widget

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    7 Favorites

    Autopsy Of A Widget - Presentation Transcript

    1. Autopsy of a Widget The Internals of a qooxdoo Widget by Fabian Jakobs @fjakobs
    2. Web Application
    3. Browser as Render Engine
    4. Primitives Image Text Rectangle
    5. Tree of Primitives •DOM tree •Events •CSS for styling •JavaScript for behavior
    6. The Body Widget
    7. The Widget •Spinner •Number input •Composed widget new qx.ui.form.Spinner(20);
    8. Static Structure: Composed Widgets
    9. Goal •Create complex Widgets by composing Widgets •Use known GUI Concepts •Abstraction over the Browser
    10. Goal •Create complex Widgets by composing Widgets •Use known GUI Concepts •Abstraction over the Browser
    11. qx.Class.define("qx.ui.form.Spinner", { extend : qx.ui.core.Widget, construct : function(value) { this.base(arguments); } });
    12. qx.Class.define("qx.ui.form.Spinner", { extend : qx.ui.core.Widget, construct : function(value) { this.base(arguments); var layout = new qx.ui.layout.Grid(); layout.setRowFlex(0, 1); layout.setRowFlex(1, 1); layout.setColumnFlex(1, 1); this._setLayout(layout); } });
    13. qx.Class.define("qx.ui.form.Spinner", { extend : qx.ui.core.Widget, construct : function(value) { this.base(arguments); var layout = new qx.ui.layout.Grid(); layout.setRowFlex(0, 1); layout.setRowFlex(1, 1); layout.setColumnFlex(1, 1); this._setLayout(layout); this._input = new qx.ui.form.TextField(value.toString()); this._add(this._input, {row: 0, column: 0, rowSpan: 2}); this._buttonUp = new qx.ui.form.Button(); this._buttonUp.setIcon("decoration/arrows/up-small.png"); this._add(this._buttonUp, {row: 0, column: 1}); this._buttonDown = new qx.ui.form.Button(); this._buttonDown.setIcon("decoration/arrows/down-small.png"); this._add(this._buttonDown, {row: 1, column: 1}); } });
    14. Demo http://demo.qooxdoo.org/current/playground
    15. DOM Structure
    16. DOM Structure new qx.ui.form.TextField("Anatomy");
    17. DOM Structure new qx.ui.form.TextField("Anatomy"); <div style="position: absolute; left: 10px; top: 10px; width: 102px; height: 22px;"> <input type="text" spellcheck="false" tabindex="1" style='position: absolute; z-index: 10; left: 6px; top: 4px; width: 90px; height: 15px; ...'> <div style="position: absolute; top: 0pt; left: 0pt; z-index: 5;"> ... </div> </div>
    18. Container <div style="position: absolute; left: 10px; top: 10px; width: 102px; height: 22px;"> <input type="text" spellcheck="false" tabindex="1" style='position: absolute; z-index: 10; left: 6px; top: 4px; width: 90px; height: 15px; ...'> <div style="position: absolute; top: 0pt; left: 0pt; z-index: 5;"> ... </div> </div>
    19. Container Decorator <div style="position: absolute; left: 10px; top: 10px; width: 102px; height: 22px;"> <input type="text" spellcheck="false" tabindex="1" style='position: absolute; z-index: 10; left: 6px; top: 4px; width: 90px; height: 15px; ...'> <div style="position: absolute; top: 0pt; left: 0pt; z-index: 5;"> ... </div> </div>
    20. Container Decorator Content <div style="position: absolute; left: 10px; top: 10px; width: 102px; height: 22px;"> <input type="text" spellcheck="false" tabindex="1" style='position: absolute; z-index: 10; left: 6px; top: 4px; width: 90px; height: 15px; ...'> <div style="position: absolute; top: 0pt; left: 0pt; z-index: 5;"> ... </div> </div>
    21. Summary •2-3 DOM elements •Absolute positioning •Fixed sizes •No explicit padding <div style="position: absolute; left: 10px; top: 10px; width: 102px; height: 22px;"> <input type="text" spellcheck="false" tabindex="1" style='position: absolute; z-index: 10; left: 6px; top: 4px; width: 90px; height: 15px; ...'> <div style="position: absolute; top: 0pt; left: 0pt; z-index: 5;"> ... </div> </div>
    22. DOM Structure Pro Con Box Model Independence 2-3 DOM Elements Flexible Styling Size Computation in JS No Cross Browser Issues
    23. Theming
    24. The Guts: Working With The DOM
    25. new qx.ui.form.TextField("Anatomy"); ??? <div style="position: absolute; left: 10px; top: 10px; width: 102px; height: 22px;"> <input type="text" spellcheck="false" tabindex="1" style='position: absolute; z-index: 10; left: 6px; top: 4px; width: 90px; height: 15px; ...'> <div style="position: absolute; top: 0pt; left: 0pt; z-index: 5;"> ... </div> </div>
    26. The DOM is a Mess •Many cross browser issues IE element.style.filter = "alpha(opacity=" + (opacity * 100) + ");"; others element.style.opacity = opacity;
    27. The DOM is a Mess •Many cross browser issues var el = document.createElement("div"); document.body.appendChild(el); •Small mistakes can degrade el.style.position = absolute; // more style changes performance
    28. The DOM is a Mess •Many cross browser issues var el = document.createElement("div"); document.body.appendChild(el); •Small mistakes can degrade el.style.position = absolute; // more style changes performance var el = document.createElement("div"); el.style.position = absolute; // more style changes document.body.appendChild(el);
    29. The DOM is a Mess •Many cross browser issues •Small mistakes can degrade performance var width = parseInt(el.style.width); var height = parseInt(el.style.height); •Reading styles/attributes is slow
    30. The DOM is a Mess •Many cross browser issues •Small mistakes can degrade performance var width = parseInt(el.style.width); var height = parseInt(el.style.height); •Reading styles/attributes is slow
    31. DOM Wrapper •Wrap DOM elements •Lazy DOM element creation •Batch DOM manipulations •Cache styles/attributes
    32. qx.Class.define("qx.ui.core.Widget", Container { extend : qx.core.Object, construct : function() { this.base(arguments); this._container = new qx.html.Element("div"); this._content = new qx.html.Element("div").setStyles({ position: "absolute", zIndex: 10, overflow: "hidden" }); this._container.add(this._content); this._decorator = new qx.html.Element("div").setStyles({ position: "absolute", zIndex: 10 }); this._container.add(this._decorator); } });
    33. qx.Class.define("qx.ui.core.Widget", Container { extend : qx.core.Object, Decorator construct : function() { this.base(arguments); this._container = new qx.html.Element("div"); this._content = new qx.html.Element("div").setStyles({ position: "absolute", zIndex: 10, overflow: "hidden" }); this._container.add(this._content); this._decorator = new qx.html.Element("div").setStyles({ position: "absolute", zIndex: 10 }); this._container.add(this._decorator); } });
    34. qx.Class.define("qx.ui.core.Widget", Container { extend : qx.core.Object, Decorator construct : function() Content { this.base(arguments); this._container = new qx.html.Element("div"); this._content = new qx.html.Element("div").setStyles({ position: "absolute", zIndex: 10, overflow: "hidden" }); this._container.add(this._content); this._decorator = new qx.html.Element("div").setStyles({ position: "absolute", zIndex: 10 }); this._container.add(this._decorator); } });
    35. DOM Wrapper Pro Con Cross browser API Memory overhead Performance Additional complexity Keeps widget code clean
    36. Dynamic Structure: Layouts
    37. Initial Sizes
    38. Initial Sizes
    39. Initial Sizes
    40. Dynamic Update
    41. Layout •Compute widgets sizes based on •Available space •Layout constraints •Preferred widget sizes •Widget size constraints
    42. Algorithm 2 Passes
    43. Algorithm 2 Passes 1st Pass Compute Preferred Size
    44. Algorithm 2 Passes 1st Pass 2nd Pass Compute Preferred Size Render Size
    45. 1st Pass Spinner Grid getSizeHint() getSizeHint() getLayout() getLayoutChildren() computeLayout(hints) TextField Button Button getSizeHint() getSizeHint() getSizeHint() measureTextHeight() getImageSize() getImageSize()
    46. 1st Pass Spinner.getSizeHint = function() { Spinner Grid return this.getLayout().getSizeHint(); } getSizeHint() getSizeHint() getLayout() getLayoutChildren() computeLayout(hints) TextField Button Button getSizeHint() getSizeHint() getSizeHint() measureTextHeight() getImageSize() getImageSize()
    47. 1st Pass Grid.getSizeHint = function() { Spinner Grid var childrenHints = []; var children =getSizeHint() this.getLayoutChildren(); getSizeHint() for (var i=0; i<children.length; i++) { getLayout() childrenHints.push(children[i].getSizeHint()); getLayoutChildren() } computeLayout(hints) return this.computeLayout(childrenHints); } TextField Button Button getSizeHint() getSizeHint() getSizeHint() measureTextHeight() getImageSize() getImageSize()
    48. 1st Pass Spinner Grid getSizeHint() TextField.getSizeHint = function() getSizeHint() { getLayout() getLayoutChildren() return { height: this.measureTextHeight(), computeLayout(hints) width: 100 } Button.getSizeHint = function() { } return this.getImageSize() } TextField Button Button getSizeHint() getSizeHint() getSizeHint() measureTextHeight() getImageSize() getImageSize()
    49. 2nd Pass Spinner Grid renderLayout(bounds) renderLayout() getLayout() getLayoutChildren() updateWidgetSize(bounds) computeChildrenSizes(bounds) TextField Button Button renderLayout() renderLayout() renderLayout() updateWidgetSize(bounds) updateWidgetSize(bounds) updateWidgetSize(bounds)
    50. 2nd Pass Spinner.renderLayout = function(bounds) Spinner { Grid this.updateWidgetSize(bounds); renderLayout(bounds) renderLayout() this.getLayout().renderLayout(bounds); getLayout() } getLayoutChildren() updateWidgetSize(bounds) computeChildrenSizes(bounds) TextField Button Button renderLayout() renderLayout() renderLayout() updateWidgetSize(bounds) updateWidgetSize(bounds) updateWidgetSize(bounds)
    51. 2nd Pass Grid.renderLayout = function(bounds) { Spinner Grid var sizes = this.computeChildrenSizes(bounds); renderLayout(bounds) var children = this.getLayoutChildren(); renderLayout() getLayout() for (var i=0; i<children.length; i++) { children[i].renderLayout(childrenSizes[i]); getLayoutChildren() } updateWidgetSize(bounds) computeChildrenSizes(bounds) } TextField Button Button renderLayout() renderLayout() renderLayout() updateWidgetSize(bounds) updateWidgetSize(bounds) updateWidgetSize(bounds)
    52. 2nd Pass Spinner Grid renderLayout(bounds) renderLayout() getLayout() getLayoutChildren() updateWidgetSize(bounds) computeChildrenSizes(bounds) Widget.renderLayout = function(bounds) { this.updateWidgetSize(bounds); } TextField Button Button renderLayout() renderLayout() renderLayout() updateWidgetSize(bounds) updateWidgetSize(bounds) updateWidgetSize(bounds)
    53. Layout Summary •Reflow computation in JavaScript •Large collection of layout managers •Highly optimized
    54. Layout Summary •Reflow computation in JavaScript •Large collection of layout managers •Highly optimized „If a feature is missing we can easily add it!“
    55. Layout Pro Con Cross Browser Slower than CSS layouts Custom Layout Managers Complex Implementation Highly Customizable Sensible Default Sizes
    56. Events
    57. „DOM events are a huge stinking pile of mess!“
    58. Different API IE W3C DOM Events attachEvent(...) addEventListener(...) e.returnValue = false e.preventDefault() e.cancelBubble = true e.stopPropagation() ... ...
    59. „It‘s getting worse“
    60. Different Features •Event capturing phase •Mouse capturing (only IE) •Both features are highly desirable
    61. „Worst ...“
    62. Different Behavior •Different mouse event sequences •keyCode and charCode depend on •browser •operating system •locale •...
    63. Goal qx.Class.define("qx.ui.form.Spinner", { extend : qx.ui.core.Widget, construct : function(value) { this.base(arguments); // ... this._buttonUp.addListener("click", this._increaseValue, this); this._buttonDown.addListener("click", this._decreaseValue, this); }, members : { _increaseValue : function() { /* .. */}, _decreaseValue : function() { /* .. */}, } });
    64. Naive e.onclick = onClick e.onkeyPress = onKeyPress
    65. Mouse Handler
    66. listen Mouse Handler
    67. listen Mouse Handler Registration
    68. listen Mouse Handler Registration
    69. listen Mouse Handler Registration qx.event.Registration.addListener(element, "click", function(e) { alert("you clicked me"); });
    70. listen Mouse Handler Registration qx.event.Registration.addListener(element, "click", function(e) { alert("you clicked me"); });
    71. listen Mouse Handler Registration qx.event.Registration.addListener(element, "click", function(e) { alert("you clicked me"); });
    72. listen Mouse Handler Registration qx.event.Registration.addListener(element, "click", function(e) { alert("you clicked me"); });
    73. listen Mouse Handler Registration qx.event.Registration.addListener(element, "click", function(e) { alert("you clicked me"); });
    74. listen Mouse Handler Registration qx.event.Registration.addListener(element, "click", function(e) { alert("you clicked me"); });
    75. listen Mouse Handler Registration qx.event.Registration.addListener(element, "click", function(e) { alert("you clicked me"); });
    76. listen Mouse Handler Registration qx.event.Registration.addListener(element, "click", function(e) { alert("you clicked me"); });
    77. listen Mouse Handler Registration qx.event.Registration.addListener(element, "click", function(e) { alert("you clicked me"); });
    78. Events Pro Con W3C DOM API Performance Mouse capturing Code Size Unified behavior
    79. Summary
    80. Composed Widgets DOM Structure Theming DOM Wrapper Layout Events
    81. Image Reference •Anatomy exhibit •University of Michigan Health Sciences Libraries Rare Book Room •http://www.flickr.com/photos/ rosefirerising/sets/ 72157606558666166
    82. Demo •http://bit.ly/39RDkP •http://bit.ly/2sllO4 •http://bit.ly/1fAevz •http://bit.ly/38ZUYR •http://bit.ly/1Rrb9O

    + Fabian JakobsFabian Jakobs, 3 weeks ago

    custom

    723 views, 7 favs, 6 embeds more stats

    With modern JavaScript frameworks like ExtJS, Sprou more

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 723
      • 567 on SlideShare
      • 156 from embeds
    • Comments 0
    • Favorites 7
    • Downloads 18
    Most viewed embeds
    • 147 views on http://news.qooxdoo.org
    • 3 views on http://speakerrate.com
    • 2 views on http://feeds2.feedburner.com
    • 2 views on http://planet.blog.tennessee.1und1.de
    • 1 views on http://planet.blog.tennessee.schlund.de

    more

    All embeds
    • 147 views on http://news.qooxdoo.org
    • 3 views on http://speakerrate.com
    • 2 views on http://feeds2.feedburner.com
    • 2 views on http://planet.blog.tennessee.1und1.de
    • 1 views on http://planet.blog.tennessee.schlund.de
    • 1 views on http://feeds.feedburner.com

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories