JavaScript and DOM Pattern Implementation

  • 6,074 views
Uploaded on

Covers implementation details of five important Ajax design patterns in terms of DOM, CSS and JavaScript.

Covers implementation details of five important Ajax design patterns in terms of DOM, CSS and JavaScript.

More in: Business , Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
6,074
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
220
Comments
0
Likes
6

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. JavaScript DOM Pattern Implementations Dave Johnson [email_address]
  • 2. Agenda
    • About me
    • Patterns Overview
    • Patterns
      • Inline Editing
      • Composite Controls
      • Popup
      • Copy and Paste
      • Live Scrolling
  • 3. About
    • Author Enterprise Ajax
    • http://blogs.nitobi.com/dave
  • 4. Nitobi
    • Nitobi co-founder, CTO
    • Located in Vancouver, Canada
    • Declarative, server integrated, Ajax user-interface components
    • User interface consulting and training services
    • Online usability service RobotReplay
  • 5.  
  • 6. Customers
  • 7. Patterns OVERVIEW
  • 8.
    • “Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice”
    • A Pattern Language
  • 9. Architectural Patterns
    • Literally.
    • MVC
    • Peer-to-peer
    • SOA
  • 10. Software Design Patterns
    • Gang of Four (GoF)
      • Creational
      • Behavioural
      • Structural
    • Others
      • Concurrency
  • 11. UI Design Patterns
    • Bill Scott and others
    • Described as
      • Problem
      • Context
      • Principle
      • Solution
      • Why / How
  • 12. Ajax Design Patterns
    • What we are talking about today
    • Applies principles from all areas:
      • MVC
      • UI
      • OOP
  • 13. Bad Patterns
    • Increased complexity
    • Does not provide re-use
    • Language hacks
    THE PROBLEMS
  • 14. Observer
    • Event = function(type) {
    • this.handlers = {};
    • this.guid = 0;
    • }
    • Event.prototype.subscribe = function(func) {
    • this.handlers[this.guid++] = func;
    • return guid;
    • }
    • Event.prototype.notify = function(evtArgs) {
    • for (var item in this.handlers) {
    • this.handlers[item].apply(this, arguments);
    • }
    • }
  • 15.
    • “The meaning of life is that it is to be lived, and it is not to be traded and conceptualized and squeezed into a pattern of systems”
    • Bruce Lee
  • 16. Programmers Are Lazy
    • “ If you have a difficult task, give it to a lazy person - they will find an easier way to do it.”
    • Hlade's Law
  • 17. Ajax Patterns - Goals
    • Making the web like the desktop
    • Improving user experience
    • More responsive applications
    • Remove web / desktop divide
    • Marriage of JavaScript, DOM, CSS
  • 18. Describing Ajax Patterns
    • What is the pattern
    • When is the pattern applied
    • Why use the pattern
    • How is the pattern implemented
  • 19. Best Practices
    • Consider the user and the developer
    • Common approaches
      • Progressive enhancement
        • http://en.wikipedia.org/wiki/Progressive_enhancement
      • Unobtrusive JavaScript
        • http://en.wikipedia.org/wiki/Unobtrusive_JavaScript
  • 20. Pitfalls
    • Cross browser
    • Cross doctype
    • I18n and localization
    • Accessibility
  • 21. THE PATTERNS
  • 22. Inline Edit
    • What edit in page without page refresh
    • When titles, tags etc
    • Why remove page refreshes
  • 23. How
    • User invited to click on data field
    • Field is replaced with an editing control
    • User blurs or saves and field is saved behind the scenes and editor removed
  • 24.  
  • 25. DOM
    • <div id=&quot;title&quot; class=&quot;editable&quot;>Edit me!</div>
  • 26. CSS
    • #title {
    • width:200px;
    • border:1px solid black;
    • cursor:pointer;
    • cursor:hand;
    • }
  • 27. Edit
    • edit: function(evt) {
    • //create the editor
    • this.editor = nitobi.html.createElement( “input”, { id : ”editor”, type : ”text”, value : this.node.innerHTML }, { width: this.node.offsetWidth, height: this.node.offsetHeight );
    • this.node.replaceChild(this.editor, this.node.firstChild);
    • //set the focus so that it is ready to go
    • this.editor.focus();
    • //attach events for bluring and key handling
    • nitobi.html.attachEvent(this.editor, &quot;blur&quot;, this.save);
    • nitobi.html.attachEvent(this.editor, &quot;keydown&quot;, this.keydown);
    • //detach the event for going into edit mode
    • nitobi.html.detachEvent(this.node, &quot;click&quot;, this.edit);
    • }
  • 28. Key Handling
    • keydown: function(evt) {
    • //check for enter key at least
    • if (evt.keyCode == 13) {
    • this.editor.blur();
    • }
    • }
  • 29. Saving
    • save: function(evt) {
    • //send the data to the server
    • var xhr = new HttpRequest();
    • xhr.onRequestComplete.subscribe(this.afterSave);
    • xhr.open(“POST”, “mysite.com”, true);
    • xhr.send(“title=“+this.editor.value);
    • //revert to the view only
    • this.node.innerHTML = this.editor.value;
    • //show an activity indicator
    • this.activity.style.display = “inline”;
    • },
    • afterSave: function(httpResponse) {
    • //concurrency pattern
    • //undo with command pattern
    • attachEvent(this.node, &quot;click&quot;, this.edit);
    • }
  • 30. Pitfalls / Best Practices
    • Potential Pitfalls
      • page contents can move when changing “modes”
      • too subtle invitation to edit
      • too many edit invitations
      • concurrency or failure
    • Best Practices
      • avoid page jitter
      • make render & edit modes same size
      • activate on click
      • deactivate on blur
  • 31. Composite Controls
    • What inline edit multiple text fields
    • When simple forms, combo box
    • Why remove page refreshes
  • 32. How
    • Create a Form JavaScript class that implements IBlurable interface
    • All form elements have key and mouse events attached through IBlurable
    • When user clicks on fields the mousedown event on the newly clicked field blocks the blur on the previous field
    • When user clicks outside of the composite control the blur event is not blocked
  • 33. Aside: Event Order
    • Click on the first name field
      • mousedown
      • focus
      • mouseup
      • click
    • Click on the last name field
      • mousedown (last name)
      • blur (first name)
      • focus (last name)
      • mouseup (last name)
      • click (last name)
    • Also consider relatedTarget / fromElement
  • 34.  
  • 35. DOM
    • <form id=&quot;form&quot; name=&quot;form&quot;>
    • <label for=&quot;first&quot;>First: </label>
    • <input name=&quot;first&quot; id=&quot;first&quot;>
    • <label for=&quot;last&quot;>Last: </label>
    • <input name=&quot;last&quot; id=&quot;last&quot;>
    • </form>
  • 36. NameForm
    • NameForm = function(node) {
    • this.form = node;
    • //setup the blurable interface
    • IBlurable.call(this, this.form.elements);
    • this.onBlur.subscribe(this.save, this);
    • }
    • //implement the interface (ie copy over the methods)
    • nitobi.lang.implement(NameForm, IBlurable);
    • NameForm.prototype.save = function(evt) {
    • //same issues as inline edit case
    • var xhr = new nitobi.ajax.HttpRequest();
    • xhr.open(&quot;POST&quot;, &quot;http://nitobi.com/name&quot;, true);
    • xhr.send(this.form);
    • };
  • 37. Pitfalls / Best Practices
    • Potential Pitfalls
      • event order differences across browsers
      • event problems on certain controls (select, scrollbars)
    • Best Practices
      • use for data validation behind the scenes on sub-forms
      • consider both keyboard (tabbing) and mouse events
  • 38. Popup
    • What display additional information
    • When details are required in context
    • Why remove page refresh
  • 39. How
    • User moves mouse over element that has mouseover event attached
    • Popup is displayed
    • User moves over another part of the trigger element firing mouseout event on a timeout
    • If show is called while waiting for a hide the hide is cancelled preventing flicker and allowing user to mouse over the contents of the popup
  • 40.  
  • 41. DOM
    • <span id=&quot;title&quot;>
    • <strong>
    • <a href=&quot;#&quot;>Iron Man</a>
    • </strong>
    • <span class=&quot;year&quot;>(2008)</span>
    • </span>
    • <div id=&quot;details&quot;>
    • When wealthy ...
    • <a href=&quot;#&quot;>(more)</a>
    • </div>
  • 42. Aside: Event Bubbling
    • Events bubble up through the DOM
    • They are also “captured”
    • Event handlers fire when trigged from any child node
  • 43. CSS
    • #details {
    • position: absolute;
    • display: none;
    • top: 0px;
    • left: 0px;
    • width: 300px;
    • height: 100px;
    • border: 1px solid black;
    • background-color: white;
    • }
  • 44. Constructor
    • Popup = function(title, detail) {
    • this.detail = detail;
    • //attach mouseover event for show
    • nitobi.html.attachEvent(title, &quot;mouseover&quot;, this.show);
    • var _t = this;
    • this.hideTimeout = null;
    • //attach a delayed mouseout event for hide
    • nitobi.html.attachEvent(title, &quot;mouseout&quot;, function() {
    • _t.hideTimeout = setTimeout(_t.hide, 200);
    • });
    • }
  • 45. Show
    • Popup.prototype.show = function(evt) {
    • if (this.hideTimeout != null) {
    • //clear the hide timeout clearTimeout(this.hideTimeout);
    • this.hideTimeout
    • } else {
    • //show the popup
    • var style = this.detail.style;
    • style.display = &quot;block&quot;;
    • style.top = (evt.clientY + 5) + &quot;px&quot;;
    • style.left = (evt.clientX + 5) + &quot;px&quot;;
    • }
    • }
  • 46. Pitfalls / Best Practices
    • Potential Pitfalls
      • mouse event bubbling causes flickering or moving of the popup
      • rogue popups
      • Interaction between trigger and contents
    • Best Practices
      • enable keyboard access
      • provide some way to close manually
      • make certain it disappears!
  • 47. Copy and Paste
    • What user can enter bulk data
    • When interop desktop and browser
    • Why remove page refreshes
  • 48. How - Copy
    • User clicks on focusable element (<a>)
    • Filter for ctrl+c on keydown event
    • Set value of hidden <textarea> to the data that is to be copied
    • Focus on the hidden <textarea>
    • Magic
    • Capture keyup event on hidden <textarea> to focus back on your control
    • <textarea> value now on OS clipboard
  • 49. How - Paste
    • User clicks on focusable element (<a>)
    • Filter for ctrl+v on keydown event
    • Focus on the hidden <textarea>
    • Magic
    • Capture keyup event on hidden <textarea>
    • Data from OS clipboard now in the <textarea> where you can access it and focus back on your control
  • 50.  
  • 51. DOM
    • <div id=&quot;copyable&quot;>
    • Copy this text
    • </div>
    • <textarea id=“clipboard”></textarea>
  • 52. CSS
    • #clipboard {
      • position: absolute;
      • left: -5000px;
    • }
  • 53. Constructor
    • var Copyable = function(node) {
    • //replace the contents with an <a> tag so that it is focusable
    • this.source = node;
    • this.source.innerHTML = &quot;<a href=&quot;#&quot; class=&quot;focusable&quot;>&quot;+this.source.innerHTML+&quot;</a>&quot;;
    • //intercept all key presses to look for ctrl+c/v
    • nitobi.html.attachEvent(this.source, &quot;keydown&quot;, this.handleKey);
    • //create the clipboard
    • this.clipboard = nitobi.html.createElement(&quot;textarea&quot;, { id : &quot;clipboard&quot;+node.id } );
    • document.body.appendChild(this.clipboard);
    • }
  • 54. handleKey
    • handleKey: function(evt) {
    • var k = evt.keyCode;
    • //offset keycode for modifier keys
    • k = k + (evt.shiftKey?256:0)+
    • (evt.ctrlKey?512:0)+
    • (evt.metaKey?1024:0);
    • //lookup the method in a map
    • var handler = this.keyMap[k];
    • //call that method
    • if (handler != null)
    • handler.call(this);
    • }
  • 55. Copy
    • copy: function() {
    • //get the data we want to copy
    • var data = this.source.firstChild.innerHTML;
    • if (!nitobi.browser.IE) {
    • //focus back control when the copy is complete
    • attachEvent(this.clipboard, &quot;keyup&quot;, this.focus);
    • //set the value, focus and select the value
    • this.clipboard.value = data;
    • this.clipboard.focus(); this.clipboard.setSelectionRange(0,data.length);
    • } else {
    • window.clipboardData.setData(&quot;Text&quot;,data);
    • }
    • }
  • 56. Paste
    • paste: function() {
    • //catch the textarea keyup to grab the results
    • nitobi.html.attachEventOnce(this.clipboard, &quot;keyup&quot;, this.pasteReady);
    • this.clipboard.focus();
    • },
    • pasteReady: function() {
    • //get the clipboard value and insert it
    • this.source.firstChild.innerHTML = this.clipboard.value;
    • //focus back on the control
    • this.source.firstChild.focus();
    • }
  • 57. Pitfalls / Best Practices
    • Pitfalls
      • user is unaware of functionality
      • keyboard short cuts don’t match OS
      • no context menu support in some browsers
    • Best Practices
      • capture ctrl/cmd+c/v/x for different OS
      • support various formats depending on use case
  • 58. Live Scrolling
    • What scroll through large datasets
    • When viewing, filtering, sorting
    • Why remove page refreshes
  • 59. How
    • Create clipping <div> and surface <div> where data goes
    • Repeat for a scrollbar
    • Connect scrollbar scroll events to position the data surface
    • Retrieve data from the server as user scrolls
  • 60.  
  • 61. DOM
    • <div id=“viewport”>
    • <div id=“surface”>
    • <div id=“data”></div>
    • </div>
    • </div>
    • <div id=“scrollcontainer&quot;>
    • <div id=&quot;scrollbar&quot;>
    • <div id=“range”></div>
    • </div>
    • </div>
  • 62. CSS
    • #scrollcontainer {
    • width: 16px;
    • height: 300px;
    • overflow: hidden;
    • }
    • #scrollbar {
    • height: 100%;
    • width: 16px;
    • //width: 17px;
    • position: relative;
    • overflow-x: hidden;
    • overflow-y: scroll;
    • }
    • #range {
    • overflow: hidden;
    • width: 1px;
    • height: 3000px;&quot;
    • }
    #viewport { position: relative; overflow: hidden; width: 300px; height: 300px; border: 1px solid black; } #surface { width: 2000px; height: 2000px; }
  • 63. Scrolling
    • var evt = “mousewheel”;
    • if (nitobi.browser.MOZ)
    • evt = “DOMMouseScroll”;
    • //attach the event to the surface
    • nitobi.html.attachEvent(
    • scollSurface, evt,
    • this.handleMouseWheel);
  • 64. Pitfalls / Best Practices
    • Potential Pitfalls
      • dual-scrollbar issue
      • sluggish performance
      • extremely large data sets
    • Best Practices
      • provide dynamic tooltip showing location within scroll
      • animate scroll
      • if desire a hybrid, use animation on paging.
      • support mouse scroll wheel
  • 65. Acknowledgements
    • Bill Scott
    • Michael Mahemoff
    • Andre Charland
  • 66. Thank You
    • Questions?
    • email: [email_address]
    • blog: blogs.nitobi.com/dave
    • book: enterpriseajax.com
    • tweets: twitter.com/davejohnson
  • 67.
    • http://flickr.com/photos/daveknapik/2115474105/
    • http://flickr.com/photos/preciouskhyatt/2153351428/
    • http://flickr.com/photos/sandcastlematt/403101240/