Slideshare.net (beta)

 

All comments

Add a comment on Slide 1

If you have a SlideShare account, login to comment; else you can comment as a guest


Showing 1-50 of 4 (more)

JavaScript and DOM Pattern Implementation

From davejohnson, 3 months ago

Covers implementation details of five important Ajax design patter more

1631 views  |  0 comments  |  3 favorites  |  35 downloads  |  2 embeds (Stats)
Embed
options

More Info

This slideshow is Public
Total Views: 1631
on Slideshare: 1557
from embeds: 74

Slideshow transcript

Slide 1: JavaScript DOM Pattern Implementations Dave Johnson dave@nitobi.com CommunityOne :: May 5 :: 2008

Slide 2: Agenda • About me • Patterns Overview • Patterns – Inline Editing – Composite Controls – Popup – Copy and Paste – Live Scrolling CommunityOne :: May 5 :: 2008

Slide 3: About • Author Enterprise Ajax • http://blogs.nitobi.com/dave CommunityOne :: May 5 :: 2008

Slide 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 CommunityOne :: May 5 :: 2008

Slide 5: CommunityOne :: May 5 :: 2008

Slide 6: Customers CommunityOne :: May 5 :: 2008

Slide 7: Patterns OVERVIEW CommunityOne :: May 5 :: 2008

Slide 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” CommunityOne :: May 5 :: 2008

Slide 9: Architectural Patterns Literally. • MVC • Peer-to-peer • SOA CommunityOne :: May 5 :: 2008

Slide 10: Software Design Patterns • Gang of Four (GoF) – Creational – Behavioural – Structural • Others – Concurrency CommunityOne :: May 5 :: 2008

Slide 11: UI Design Patterns • Bill Scott and others • Described as – Problem – Context – Principle – Solution – Why / How CommunityOne :: May 5 :: 2008

Slide 12: Ajax Design Patterns • What we are talking about today • Applies principles from all areas: – MVC – UI – OOP CommunityOne :: May 5 :: 2008

Slide 13: Bad Patterns • Increased complexity • Does not provide re-use • Language hacks THE PROBLEMS CommunityOne :: May 5 :: 2008

Slide 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); } } CommunityOne :: May 5 :: 2008

Slide 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 CommunityOne :: May 5 :: 2008

Slide 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 CommunityOne :: May 5 :: 2008

Slide 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 CommunityOne :: May 5 :: 2008

Slide 18: Describing Ajax Patterns What is the pattern When is the pattern applied Why use the pattern How is the pattern implemented CommunityOne :: May 5 :: 2008

Slide 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 CommunityOne :: May 5 :: 2008

Slide 20: Pitfalls • Cross browser • Cross doctype • I18n and localization • Accessibility CommunityOne :: May 5 :: 2008

Slide 21: THE PATTERNS CommunityOne :: May 5 :: 2008

Slide 22: Inline Edit • What edit in page without page refresh • When titles, tags etc • Why remove page refreshes CommunityOne :: May 5 :: 2008

Slide 23: How 1. User invited to click on data field 2. Field is replaced with an editing control 3. User blurs or saves and field is saved behind the scenes and editor removed CommunityOne :: May 5 :: 2008

Slide 24: CommunityOne :: May 5 :: 2008

Slide 25: DOM <div id="title" class="editable">Edit me!</div> CommunityOne :: May 5 :: 2008

Slide 26: CSS #title { width:200px; border:1px solid black; cursor:pointer; cursor:hand; } CommunityOne :: May 5 :: 2008

Slide 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, "blur", this.save); nitobi.html.attachEvent(this.editor, "keydown", this.keydown); //detach the event for going into edit mode nitobi.html.detachEvent(this.node, "click", this.edit); } CommunityOne :: May 5 :: 2008

Slide 28: Key Handling keydown: function(evt) { //check for enter key at least if (evt.keyCode == 13) { this.editor.blur(); } } CommunityOne :: May 5 :: 2008

Slide 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, "click", this.edit); } CommunityOne :: May 5 :: 2008

Slide 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 CommunityOne :: May 5 :: 2008

Slide 31: Composite Controls • What inline edit multiple text fields • When simple forms, combo box • Why remove page refreshes CommunityOne :: May 5 :: 2008

Slide 32: How 1. Create a Form JavaScript class that implements IBlurable interface 2. All form elements have key and mouse events attached through IBlurable 3. When user clicks on fields the mousedown event on the newly clicked field blocks the blur on the previous field 4. When user clicks outside of the composite control the blur event is not blocked :: 2008 CommunityOne :: May 5

Slide 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 5 :: 2008 CommunityOne :: May

Slide 34: CommunityOne :: May 5 :: 2008

Slide 35: DOM <form id="form" name="form"> <label for="first">First: </label> <input name="first" id="first"> <label for="last">Last: </label> <input name="last" id="last"> </form> CommunityOne :: May 5 :: 2008

Slide 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("POST", "http://nitobi.com/name", true); xhr.send(this.form); }; CommunityOne :: May 5 :: 2008

Slide 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 CommunityOne :: May 5 :: 2008

Slide 38: Popup • What display additional information • When details are required in context • Why remove page refresh CommunityOne :: May 5 :: 2008

Slide 39: How 1. User moves mouse over element that has mouseover event attached 2. Popup is displayed 3. User moves over another part of the trigger element firing mouseout event on a timeout 4. 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 CommunityOne :: May 5 :: 2008

Slide 40: CommunityOne :: May 5 :: 2008

Slide 41: DOM <span id="title"> <strong> <a href="#">Iron Man</a> </strong> <span class="year">(2008)</span> </span> <div id="details"> When wealthy ... <a href="#">(more)</a> </div> CommunityOne :: May 5 :: 2008

Slide 42: Aside: Event Bubbling • Events bubble up through the DOM • They are also “captured” • Event handlers fire when trigged from any child node CommunityOne :: May 5 :: 2008

Slide 43: CSS #details { position: absolute; display: none; top: 0px; left: 0px; width: 300px; height: 100px; border: 1px solid black; background-color: white; } CommunityOne :: May 5 :: 2008

Slide 44: Constructor Popup = function(title, detail) { this.detail = detail; //attach mouseover event for show nitobi.html.attachEvent(title, "mouseover", this.show); var _t = this; this.hideTimeout = null; //attach a delayed mouseout event for hide nitobi.html.attachEvent(title, "mouseout", function() { _t.hideTimeout = setTimeout(_t.hide, 200); }); } CommunityOne :: May 5 :: 2008

Slide 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 = "block"; style.top = (evt.clientY + 5) + "px"; style.left = (evt.clientX + 5) + "px"; } } CommunityOne :: May 5 :: 2008

Slide 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! CommunityOne :: May 5 :: 2008

Slide 47: Copy and Paste • What user can enter bulk data • When interop desktop and browser • Why remove page refreshes CommunityOne :: May 5 :: 2008

Slide 48: How - Copy 1. User clicks on focusable element (<a>) 2. Filter for ctrl+c on keydown event 3. Set value of hidden <textarea> to the data that is to be copied 4. Focus on the hidden <textarea> 5. Magic 6. Capture keyup event on hidden <textarea> to focus back on your control CommunityOne :: May 5 :: 2008

Slide 49: How - Paste 1. User clicks on focusable element (<a>) 2. Filter for ctrl+v on keydown event 3. Focus on the hidden <textarea> 4. Magic 5. Capture keyup event on hidden <textarea> 6. Data from OS clipboard now in the <textarea> where you can access it and focus back on your control CommunityOne :: May 5 :: 2008

Slide 50: CommunityOne :: May 5 :: 2008

Slide 51: DOM <div id="copyable"> Copy this text </div> <textarea id=“clipboard”></textarea> CommunityOne :: May 5 :: 2008

Slide 52: CSS #clipboard { position: absolute; left: -5000px; } CommunityOne :: May 5 :: 2008

Slide 53: Constructor var Copyable = function(node) { //replace the contents with an <a> tag so that it is focusable this.source = node; this.source.innerHTML = "<a href="#" class="focusable">"+this.source.innerHTML+"</a>"; //intercept all key presses to look for ctrl+c/v nitobi.html.attachEvent(this.source, "keydown", this.handleKey); //create the clipboard this.clipboard = nitobi.html.createElement("textarea", { id : "clipboard"+node.id } ); document.body.appendChild(this.clipboard); } CommunityOne :: May 5 :: 2008

Slide 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); } CommunityOne :: May 5 :: 2008

Slide 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, "keyup", 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("Text",data); } } CommunityOne :: May 5 :: 2008

Slide 56: Paste paste: function() { //catch the textarea keyup to grab the results nitobi.html.attachEventOnce(this.clipboard, "keyup", 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(); } CommunityOne :: May 5 :: 2008

Slide 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 CommunityOne :: May 5 :: 2008

Slide 58: Live Scrolling • What scroll through large datasets • When viewing, filtering, sorting • Why remove page refreshes CommunityOne :: May 5 :: 2008

Slide 59: How 1. Create clipping <div> and surface <div> where data goes 2. Repeat for a scrollbar 3. Connect scrollbar scroll events to position the data surface 4. Retrieve data from the server as user scrolls CommunityOne :: May 5 :: 2008

Slide 60: CommunityOne :: May 5 :: 2008

Slide 61: DOM <div id=“viewport”> <div id=“surface”> <div id=“data”></div> </div> </div> <div id=“scrollcontainer"> <div id="scrollbar"> <div id=“range”></div> </div> </div> CommunityOne :: May 5 :: 2008

Slide 62: CSS #viewport { #scrollcontainer { position: relative; width: 16px; overflow: hidden; height: 300px; width: 300px; overflow: hidden; height: 300px; } border: 1px solid black; #scrollbar { } height: 100%; width: 16px; #surface { //width: 17px; width: 2000px; position: relative; height: 2000px; overflow-x: hidden; } overflow-y: scroll; } #range { overflow: hidden; width: 1px; height: 3000px;" } CommunityOne :: May 5 :: 2008

Slide 63: Scrolling var evt = “mousewheel”; if (nitobi.browser.MOZ) evt = “DOMMouseScroll”; //attach the event to the surface nitobi.html.attachEvent( scollSurface, evt, this.handleMouseWheel); CommunityOne :: May 5 :: 2008

Slide 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. CommunityOne :: May 5 :: 2008

Slide 65: Acknowledgements • Bill Scott • Michael Mahemoff • Andre Charland CommunityOne :: May 5 :: 2008

Slide 66: Thank You Questions? email: dave@nitobi.com blog: blogs.nitobi.com/dave book: enterpriseajax.com tweets: twitter.com/davejohnson CommunityOne :: May 5 :: 2008

Slide 67: http://flickr.com/photos/daveknapik/2115474105/ http://flickr.com/photos/preciouskhyatt/2153351428/ http://flickr.com/photos/sandcastlematt/403101240/ CommunityOne :: May 5 :: 2008