SlideShare une entreprise Scribd logo
1  sur  43
Beyond the DOM:
             Sane Structure for JS Apps
             Rebecca Murphey • @rmurphey • FrontTrends 2012



Thursday, April 26, 12
rmurphey.com • @rmurphey • bocoup.com




Thursday, April 26, 12
function ObjInlineDown(e) {
                   if (is.ie) e = event
                   if (is.ie && ! is.ieMac && e.button != 1 && e.button != 2) return
                   if (is.ieMac && e.button != 0) return
                   if (is.ns && ! is.ns4 && e.button != 0 && e.button != 2) return
                   if (is.ns4 && e.which != 1 && e.which != 3) return
                   this.onSelect()
                   this.onDown()
                 }

                 function ObjInlineUp(e) {
                   if (is.ie) e = event
                   if (is.ie && ! is.ieMac && e.button != 1 && e.button != 2) return
                   if (is.ieMac && e.button != 0) return
                   if (is.ns && ! is.ns4 && ! is.nsMac && e.button != 0 && e.button != 2) return
                   if (is.ns4 && e.which != 1 && e.which != 3) return
                   if ((!is.ns4 && e.button == 2) || (is.ns4 && e.which == 3)) {
                     if (this.hasOnRUp) {
                       document.oncontextmenu = ocmNone
                       this.onRUp()
                       setTimeout("document.oncontextmenu = ocmOrig", 100)
                     }
                   }
                   else if (this.hasOnUp) this.onUp()
                 }




Thursday, April 26, 12
Thursday, April 26, 12
Thursday, April 26, 12
Thursday, April 26, 12
<div id="searchForm">
                     <form class="form-inline">
                          <input type="text" placeholder="Enter your search term">
                          <button type="submit">Search</button>
                     </form>
                     <ul id="searchResults"></ul>
                   </div>




Thursday, April 26, 12
$("#searchForm form").submit(function(e) {
                  alert('submit');
                  e.preventDefault();

                    var term = $('#searchForm input').val(),
                        req = $.getJSON('http://search.twitter.com/search.json?callback=?&q=' +
                              encodeURIComponent(term));

                    req.then(function(resp) {
                      var resultsHTML = $.map(resp.results, function(r) {
                        return '<li>' +
                          '<p class="tweet">' + r.text + '</p>' +
                          '<p class="username">' + r.from_user + '</p>' +
                        '</li>';
                      }).join('');

                    $('#searchResults').html(resultsHTML);
                  });
                });




Thursday, April 26, 12
Thursday, April 26, 12
Thursday, April 26, 12
a').hasClass('md_fullpage')) {
                           // alert('clicked section is current section AND fullpage mode is active; teaser should load');
                       // Minimize
                           jQuery('#md_tabs_navigation a').removeClass('md_fullpage');
                           jQuery('.md_body').hide();
                           jQuery('#md_feature').slideDown('normal',function(){
                                var bodyContent = jQuery('#md_body_'+ section);
                               bodyContent.fadeOut('normal',function(){
                                    jQuery('#md_tabs_navigation a').each(function(){
                                        var thisSection = jQuery(this).html().replace('<span<','').replace('</span<','');
                                        var thisSection_comp = thisSection.toLowerCase().replace(' ','_');
                                        jQuery('#md_body_'+ thisSection_comp).load(
                                            '/app/modules/info/loadTeaser.php?sect='+ thisSection_comp,
                                            function(){
                                                tb_init('.md_body a.thickbox, .md_body area.thickbox, .md_body input.thickbox');
                                                bodyContent.animate({ height: 'toggle', opacity: 'toggle' },"slow");
                                            }
                                        );
                                    });
                               });
                           });
                           jQuery('#expandtabs span').empty().append('Expand Tabs');
                       } else {
                       // if the clicked section is NOT the current section OR we're NOT in full page mode
                       // then let's go to full page mode and show the whole tab
                       // Maximize
                           // alert('clicked section is not the current section OR full page mode is not active; full section should
                  load');
                           jQuery('#md_tabs_navigation li').removeClass('current');
                           jQuery('#md_tab_'+ section).addClass('current');
                           jQuery('#md_tabs_navigation a').addClass('md_fullpage');
                           jQuery('.md_body').hide();
                           jQuery('#md_feature').slideUp('normal',function(){
                                var bodyContent = jQuery('#md_body_'+ section);
                               bodyContent.fadeOut('normal',function(){
                                    bodyContent.empty();
                                    var pageLoader = 'info/loadSection.php?sect='+ section;
                                    if (section == 'contact_us') {
                                         pageLoader = 'contact/loadContactForm.php?form_id=1';
                                    }
                                    bodyContent.load('/app/modules/'+ pageLoader,function(){
                                        // ADD THICKBOXES
                                        tb_init('.md_body a.thickbox, .md_body area.thickbox, .md_body input.thickbox');
                                        $recent_news_links = jQuery('ul.md_news li a.recent_news_link');
                                        $recent_news_links
                                            .unbind('click')
                                            .each(function(){
                                                var hrefMod = this.href;
                                                hrefMod = hrefMod.replace(/article/,'loadNews').replace(/storyid/,'id');
                                                this.href = hrefMod;
                                            })
                                            .click(function(){
Thursday, April 26, 12                          var t = this.title || this.name || null;
Thursday, April 26, 12
$("#searchForm form").submit(function(e) {
                                            alert('submit');
                          search input      e.preventDefault();

                                            var term = $('#searchForm input').val(),
                                                req = $.getJSON('http://search.twitter.com
                                                      encodeURIComponent(term));

                                            req.then(function(resp) {
                          search data         var resultsHTML = $.map(resp.results, functi
                                                return '<li>' +
                                                  '<p class="tweet">' + r.text + '</p>' +
                                                  '<p class="username">' + r.from_user + '
                                                '</li>';
                                              }).join('');

                                              $('#searchResults').html(resultsHTML);
                         search results
                                            });
                                          });




Thursday, April 26, 12
Thursday, April 26, 12
Thursday, April 26, 12
Thursday, April 26, 12
Thursday, April 26, 12
Thursday, April 26, 12
define([
                   'jquery',
                   'text!template.html'
                 ], function($, html) {
                   return function() {
                      $('body').append(html);
                   };
                 });




Thursday, April 26, 12
<script data-main="app/config" src="/lib/require.js"></script>




Thursday, April 26, 12
require.config({
                   deps : [ 'main' ],

                         paths : {
                           // JavaScript folders
                           lib : '../lib',
                           plugins : '../lib/plugins',
                           tests : '../tests',
                           app : '.',

                           // Libraries
                           jquery : '../lib/jquery',
                           underscore : '../lib/underscore',
                           backbone : '../lib/backbone',

                           text : '../lib/plugins/text'
                   }
                 });




Thursday, April 26, 12
app/main


                 require([
                   'use!backbone',
                   'jquery',
                   'router',
                   'models/app'
                 ], function(B, $, Router, app) {
                   $(function() {
                     app.router = new Router();
                     B.history.start();
                   });
                 });




Thursday, April 26, 12
Thursday, April 26, 12
views display data, announce user interaction,
                 and await further instruction
                 models & collections manage application
                 state and communicate with the server
                 controllers set up views, transport messages
                 from views to models & collections




Thursday, April 26, 12
app/views/searchForm   app/views/recentSearches




              app/views/results




Thursday, April 26, 12
app/controllers/search




                         #mainbar      #sidebar




Thursday, April 26, 12
searches collection keeps track of recent
                 search terms
                 search data collection fetches results from
                 the server for a given search term
                 app model keeps track of general application
                 state, including the current search
                 search model for representing individual
                 searches



Thursday, April 26, 12
app/views/searchForm




                                             search controller




               server              search data                   searches collection
                                                                      app model




                                                                    app/views/recentSearches




                         app/views/results


Thursday, April 26, 12
$("#searchForm form").submit(function(e) {
                      alert('submit');
                      e.preventDefault();

                         var term = $('#searchForm input').val(),
                             req = $.getJSON('http://search.twitter.com/search.json?callba
                                   encodeURIComponent(term));

                         req.then(function(resp) {
                           var resultsHTML = $.map(resp.results, function(r) {
                             return '<li>' +
                               '<p class="tweet">' + r.text + '</p>' +
                               '<p class="username">' + r.from_user + '</p>' +
                             '</li>';
                           }).join('');

                        $('#searchResults').html(resultsHTML);
                      });
                    });




Thursday, April 26, 12
app/views/searchForm




                                             search controller




               server              search data                   searches collection
                                                                      app model




                                                                    app/views/recentSearches




                         app/views/results


Thursday, April 26, 12
prepare : function() {
                            _.bindAll(this, 'release', '_onSearch', '_disable');
                         },

                         events : {
                           'submit .search-form' :   '_onSearch'
                         },

                         _onSearch : function(e) {
                           e.preventDefault();
                           if (this.disabled) { return; }

                           var term = $.trim(this.$('.js-input').val());
                           if (!term) { return; }
                           this._disable();
                           this.trigger('search', term);
                         },

                         release : function() {
                           this.disabled = false;
                           this.$('.js-submit').removeAttr('disabled');
                         },

Thursday, April 26, 12
searchForm.on('search', update);

                         function update(t) {
                           var term              = $.trim(t),
                               existing          = searches.where({ term : term }),
                               dfd               = $.Deferred(),
                               search;

                             app.set('currentSearch', term);

                             if (term) {
                               if (existing.length) {
                                 search = existing[0];
                                 search.update();
                               } else {
                                 search = new Search({ term : term });
                                 searches.add(search);
                               }

                               searchData.fetch({ data : { term : term } })
                                 .then(dfd.resolve, dfd.reject)
                                 .always(searchForm.release);

                               app.router.navigate('search/' + term);
                             } else {
                               dfd.resolve();
                             }

                             return dfd;
                         }



Thursday, April 26, 12
it("should announce the form submission", function() {
                           var t;

                           sf.on('search', function(term) {
                             t = term;
                           });

                           el.find('.js-input').val('searchterm');
                           el.find('.search-form').submit();
                           expect(t).to.be('searchterm');
                         });




Thursday, April 26, 12
it("should update the page when the search form announces a search", function(done) {
                     var searchFormEl = $('.component.search-form').parent(),
                         searchForm = _.filter(s.views, function(v) {
                           return v.$el[0] === searchFormEl[0];
                         })[0];

                         s.searchData.on('change', function() {
                           expect($('.component.results').html()).to.contain('srchr');
                           expect($('.component.recent-searches').html()).to.contain('srchr');
                           expect(navigatedTo).to.be('search/srchr');
                           done();
                         });

                     searchForm.trigger('search', 'srchr');
                   });




Thursday, April 26, 12
app/views/searchForm




                                             search controller




               server              search data                   searches collection
                                                                      app model




                                                                    app/views/recentSearches




                         app/views/results


Thursday, April 26, 12
function update(t) {
                           var term             = $.trim(t),
                               existing         = searches.where({ term : term }),
                               dfd              = $.Deferred(),
                               search;

                             app.set('currentSearch', term);

                             if (term) {
                               if (existing.length) {
                                 search = existing[0];
                                 search.update();
                               } else {
                                 search = new Search({ term : term });
                                 searches.add(search);
                               }

                              searchData.fetch({ data : { term : term } })
                                .then(dfd.resolve, dfd.reject)
                                .always(searchForm.release);

                               app.router.navigate('search/' + term);
                             } else {
                               dfd.resolve();
                             }

                             return dfd;
                         }




Thursday, April 26, 12
this.bindTo(this.searchData, 'add change', this._update);
                 this.bindTo(this.searchData, 'fetching', function() {
                   this._empty();
                   this.reset();
                 });




Thursday, April 26, 12
Thursday, April 26, 12
function update(t) {
                           var term              = $.trim(t),
                               existing          = searches.where({ term : term }),
                               search;

                             app.set('currentSearch', term);

                             if (existing.length) {
                               search = existing[0];
                               search.update();
                             } else {
                               search = new Search({ term : term });
                               searches.add(search);
                             }

                             searchData.fetch({ data : { term : term } })
                               .always(searchForm.release);

                             app.router.navigate('search/' + term);
                         }




Thursday, April 26, 12
describe("#update", function() {
                  it("should update the time", function(done) {
                    var search = new Search(),
                        oldTime = search.get('time');

                    setTimeout(function() {
                      search.update();
                      expect(search.get('time')).to.be.greaterThan(oldTime);
                      done();
                    }, 1000);
                  });
                });




Thursday, April 26, 12
it("should update when there is a new search", function() {
                      expect(el.html()).not.to.contain('baz');
                      rs.currentSearch = function() { return 'baz'; };
                      rs.searches.add({ term : 'baz' });
                      expect(el.html()).to.contain('baz');
                      expect(el.find('.active').html()).to.contain('baz');
                    });




Thursday, April 26, 12
memory management
                 requirejs builds for production
                 multi-page apps w/history api




Thursday, April 26, 12
rmurphey.com • @rmurphey • bocoup.com

                            github.com/rmurphey/srchr-demo




Thursday, April 26, 12

Contenu connexe

Tendances

A New Baseline for Front-End Devs
A New Baseline for Front-End DevsA New Baseline for Front-End Devs
A New Baseline for Front-End DevsRebecca Murphey
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
Using Objects to Organize your jQuery Code
Using Objects to Organize your jQuery CodeUsing Objects to Organize your jQuery Code
Using Objects to Organize your jQuery CodeRebecca Murphey
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
Using Templates to Achieve Awesomer Architecture
Using Templates to Achieve Awesomer ArchitectureUsing Templates to Achieve Awesomer Architecture
Using Templates to Achieve Awesomer ArchitectureGarann Means
 
Intro to Advanced JavaScript
Intro to Advanced JavaScriptIntro to Advanced JavaScript
Intro to Advanced JavaScriptryanstout
 
Jqeury ajax plugins
Jqeury ajax pluginsJqeury ajax plugins
Jqeury ajax pluginsInbal Geffen
 
Chaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreChaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreNicolas Carlo
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonKris Wallsmith
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mockingKonstantin Kudryashov
 
Data20161007
Data20161007Data20161007
Data20161007capegmail
 
Cleaner, Leaner, Meaner: Refactoring your jQuery
Cleaner, Leaner, Meaner: Refactoring your jQueryCleaner, Leaner, Meaner: Refactoring your jQuery
Cleaner, Leaner, Meaner: Refactoring your jQueryRebecca Murphey
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistenceHugo Hamon
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkG Woo
 
Love and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayLove and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayKris Wallsmith
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design PatternsHugo Hamon
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleHugo Hamon
 

Tendances (20)

A New Baseline for Front-End Devs
A New Baseline for Front-End DevsA New Baseline for Front-End Devs
A New Baseline for Front-End Devs
 
Dojo Confessions
Dojo ConfessionsDojo Confessions
Dojo Confessions
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
Using Objects to Organize your jQuery Code
Using Objects to Organize your jQuery CodeUsing Objects to Organize your jQuery Code
Using Objects to Organize your jQuery Code
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Matters of State
Matters of StateMatters of State
Matters of State
 
Bacbkone js
Bacbkone jsBacbkone js
Bacbkone js
 
Using Templates to Achieve Awesomer Architecture
Using Templates to Achieve Awesomer ArchitectureUsing Templates to Achieve Awesomer Architecture
Using Templates to Achieve Awesomer Architecture
 
Intro to Advanced JavaScript
Intro to Advanced JavaScriptIntro to Advanced JavaScript
Intro to Advanced JavaScript
 
Jqeury ajax plugins
Jqeury ajax pluginsJqeury ajax plugins
Jqeury ajax plugins
 
Chaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscoreChaining and function composition with lodash / underscore
Chaining and function composition with lodash / underscore
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-london
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
 
Data20161007
Data20161007Data20161007
Data20161007
 
Cleaner, Leaner, Meaner: Refactoring your jQuery
Cleaner, Leaner, Meaner: Refactoring your jQueryCleaner, Leaner, Meaner: Refactoring your jQuery
Cleaner, Leaner, Meaner: Refactoring your jQuery
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
PHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php frameworkPHP 5.3 and Lithium: the most rad php framework
PHP 5.3 and Lithium: the most rad php framework
 
Love and Loss: A Symfony Security Play
Love and Loss: A Symfony Security PlayLove and Loss: A Symfony Security Play
Love and Loss: A Symfony Security Play
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 

Similaire à Beyond the DOM: Sane Structure for JS Apps

Building evented single page applications
Building evented single page applicationsBuilding evented single page applications
Building evented single page applicationsSteve Smith
 
Building Evented Single Page Applications
Building Evented Single Page ApplicationsBuilding Evented Single Page Applications
Building Evented Single Page ApplicationsSteve Smith
 
[removed] $file, removeRemove}, list #su.docx
[removed] $file, removeRemove}, list #su.docx[removed] $file, removeRemove}, list #su.docx
[removed] $file, removeRemove}, list #su.docxgerardkortney
 
Writing Maintainable JavaScript
Writing Maintainable JavaScriptWriting Maintainable JavaScript
Writing Maintainable JavaScriptAndrew Dupont
 
Object-Oriented JavaScript
Object-Oriented JavaScriptObject-Oriented JavaScript
Object-Oriented JavaScriptkvangork
 
Object-Oriented Javascript
Object-Oriented JavascriptObject-Oriented Javascript
Object-Oriented Javascriptkvangork
 
international PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretsinternational PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretssmueller_sandsmedia
 
Advanced jQuery
Advanced jQueryAdvanced jQuery
Advanced jQuerysergioafp
 
Taming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsTaming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsJarod Ferguson
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
JQuery Presentation
JQuery PresentationJQuery Presentation
JQuery PresentationSony Jain
 
How to Bring Common UI Patterns to ADF
How to Bring Common UI Patterns to ADF How to Bring Common UI Patterns to ADF
How to Bring Common UI Patterns to ADF Luc Bors
 
jQuery Data Manipulate API - A source code dissecting journey
jQuery Data Manipulate API - A source code dissecting journeyjQuery Data Manipulate API - A source code dissecting journey
jQuery Data Manipulate API - A source code dissecting journeyHuiyi Yan
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejsNick Lee
 
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docxsrcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docxwhitneyleman54422
 

Similaire à Beyond the DOM: Sane Structure for JS Apps (20)

Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
Building evented single page applications
Building evented single page applicationsBuilding evented single page applications
Building evented single page applications
 
Building Evented Single Page Applications
Building Evented Single Page ApplicationsBuilding Evented Single Page Applications
Building Evented Single Page Applications
 
[removed] $file, removeRemove}, list #su.docx
[removed] $file, removeRemove}, list #su.docx[removed] $file, removeRemove}, list #su.docx
[removed] $file, removeRemove}, list #su.docx
 
Writing Maintainable JavaScript
Writing Maintainable JavaScriptWriting Maintainable JavaScript
Writing Maintainable JavaScript
 
Object-Oriented JavaScript
Object-Oriented JavaScriptObject-Oriented JavaScript
Object-Oriented JavaScript
 
Object-Oriented Javascript
Object-Oriented JavascriptObject-Oriented Javascript
Object-Oriented Javascript
 
jQuery secrets
jQuery secretsjQuery secrets
jQuery secrets
 
jQuery secrets
jQuery secretsjQuery secrets
jQuery secrets
 
international PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secretsinternational PHP2011_Bastian Feder_jQuery's Secrets
international PHP2011_Bastian Feder_jQuery's Secrets
 
Advanced jQuery
Advanced jQueryAdvanced jQuery
Advanced jQuery
 
Taming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsTaming that client side mess with Backbone.js
Taming that client side mess with Backbone.js
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Introducing jQuery
Introducing jQueryIntroducing jQuery
Introducing jQuery
 
How te bring common UI patterns to ADF
How te bring common UI patterns to ADFHow te bring common UI patterns to ADF
How te bring common UI patterns to ADF
 
JQuery Presentation
JQuery PresentationJQuery Presentation
JQuery Presentation
 
How to Bring Common UI Patterns to ADF
How to Bring Common UI Patterns to ADF How to Bring Common UI Patterns to ADF
How to Bring Common UI Patterns to ADF
 
jQuery Data Manipulate API - A source code dissecting journey
jQuery Data Manipulate API - A source code dissecting journeyjQuery Data Manipulate API - A source code dissecting journey
jQuery Data Manipulate API - A source code dissecting journey
 
Understanding backbonejs
Understanding backbonejsUnderstanding backbonejs
Understanding backbonejs
 
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docxsrcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
 

Plus de Rebecca Murphey

Plus de Rebecca Murphey (7)

Getting Started with Mulberry
Getting Started with MulberryGetting Started with Mulberry
Getting Started with Mulberry
 
Introducing Mulberry
Introducing MulberryIntroducing Mulberry
Introducing Mulberry
 
DojoConf: Building Large Apps
DojoConf: Building Large AppsDojoConf: Building Large Apps
DojoConf: Building Large Apps
 
Lessons from-a-rewrite-gotham
Lessons from-a-rewrite-gothamLessons from-a-rewrite-gotham
Lessons from-a-rewrite-gotham
 
Lessons from a Rewrite
Lessons from a RewriteLessons from a Rewrite
Lessons from a Rewrite
 
Modern JavaScript
Modern JavaScriptModern JavaScript
Modern JavaScript
 
The jQuery Divide
The jQuery DivideThe jQuery Divide
The jQuery Divide
 

Dernier

Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 

Dernier (20)

Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 

Beyond the DOM: Sane Structure for JS Apps

  • 1. Beyond the DOM: Sane Structure for JS Apps Rebecca Murphey • @rmurphey • FrontTrends 2012 Thursday, April 26, 12
  • 2. rmurphey.com • @rmurphey • bocoup.com Thursday, April 26, 12
  • 3. function ObjInlineDown(e) { if (is.ie) e = event if (is.ie && ! is.ieMac && e.button != 1 && e.button != 2) return if (is.ieMac && e.button != 0) return if (is.ns && ! is.ns4 && e.button != 0 && e.button != 2) return if (is.ns4 && e.which != 1 && e.which != 3) return this.onSelect() this.onDown() } function ObjInlineUp(e) { if (is.ie) e = event if (is.ie && ! is.ieMac && e.button != 1 && e.button != 2) return if (is.ieMac && e.button != 0) return if (is.ns && ! is.ns4 && ! is.nsMac && e.button != 0 && e.button != 2) return if (is.ns4 && e.which != 1 && e.which != 3) return if ((!is.ns4 && e.button == 2) || (is.ns4 && e.which == 3)) { if (this.hasOnRUp) { document.oncontextmenu = ocmNone this.onRUp() setTimeout("document.oncontextmenu = ocmOrig", 100) } } else if (this.hasOnUp) this.onUp() } Thursday, April 26, 12
  • 7. <div id="searchForm"> <form class="form-inline"> <input type="text" placeholder="Enter your search term"> <button type="submit">Search</button> </form> <ul id="searchResults"></ul> </div> Thursday, April 26, 12
  • 8. $("#searchForm form").submit(function(e) { alert('submit'); e.preventDefault(); var term = $('#searchForm input').val(), req = $.getJSON('http://search.twitter.com/search.json?callback=?&q=' + encodeURIComponent(term)); req.then(function(resp) { var resultsHTML = $.map(resp.results, function(r) { return '<li>' + '<p class="tweet">' + r.text + '</p>' + '<p class="username">' + r.from_user + '</p>' + '</li>'; }).join(''); $('#searchResults').html(resultsHTML); }); }); Thursday, April 26, 12
  • 11. a').hasClass('md_fullpage')) { // alert('clicked section is current section AND fullpage mode is active; teaser should load'); // Minimize jQuery('#md_tabs_navigation a').removeClass('md_fullpage'); jQuery('.md_body').hide(); jQuery('#md_feature').slideDown('normal',function(){ var bodyContent = jQuery('#md_body_'+ section); bodyContent.fadeOut('normal',function(){ jQuery('#md_tabs_navigation a').each(function(){ var thisSection = jQuery(this).html().replace('<span<','').replace('</span<',''); var thisSection_comp = thisSection.toLowerCase().replace(' ','_'); jQuery('#md_body_'+ thisSection_comp).load( '/app/modules/info/loadTeaser.php?sect='+ thisSection_comp, function(){ tb_init('.md_body a.thickbox, .md_body area.thickbox, .md_body input.thickbox'); bodyContent.animate({ height: 'toggle', opacity: 'toggle' },"slow"); } ); }); }); }); jQuery('#expandtabs span').empty().append('Expand Tabs'); } else { // if the clicked section is NOT the current section OR we're NOT in full page mode // then let's go to full page mode and show the whole tab // Maximize // alert('clicked section is not the current section OR full page mode is not active; full section should load'); jQuery('#md_tabs_navigation li').removeClass('current'); jQuery('#md_tab_'+ section).addClass('current'); jQuery('#md_tabs_navigation a').addClass('md_fullpage'); jQuery('.md_body').hide(); jQuery('#md_feature').slideUp('normal',function(){ var bodyContent = jQuery('#md_body_'+ section); bodyContent.fadeOut('normal',function(){ bodyContent.empty(); var pageLoader = 'info/loadSection.php?sect='+ section; if (section == 'contact_us') { pageLoader = 'contact/loadContactForm.php?form_id=1'; } bodyContent.load('/app/modules/'+ pageLoader,function(){ // ADD THICKBOXES tb_init('.md_body a.thickbox, .md_body area.thickbox, .md_body input.thickbox'); $recent_news_links = jQuery('ul.md_news li a.recent_news_link'); $recent_news_links .unbind('click') .each(function(){ var hrefMod = this.href; hrefMod = hrefMod.replace(/article/,'loadNews').replace(/storyid/,'id'); this.href = hrefMod; }) .click(function(){ Thursday, April 26, 12 var t = this.title || this.name || null;
  • 13. $("#searchForm form").submit(function(e) { alert('submit'); search input e.preventDefault(); var term = $('#searchForm input').val(), req = $.getJSON('http://search.twitter.com encodeURIComponent(term)); req.then(function(resp) { search data var resultsHTML = $.map(resp.results, functi return '<li>' + '<p class="tweet">' + r.text + '</p>' + '<p class="username">' + r.from_user + ' '</li>'; }).join(''); $('#searchResults').html(resultsHTML); search results }); }); Thursday, April 26, 12
  • 19. define([ 'jquery', 'text!template.html' ], function($, html) { return function() { $('body').append(html); }; }); Thursday, April 26, 12
  • 21. require.config({ deps : [ 'main' ], paths : { // JavaScript folders lib : '../lib', plugins : '../lib/plugins', tests : '../tests', app : '.', // Libraries jquery : '../lib/jquery', underscore : '../lib/underscore', backbone : '../lib/backbone', text : '../lib/plugins/text' } }); Thursday, April 26, 12
  • 22. app/main require([ 'use!backbone', 'jquery', 'router', 'models/app' ], function(B, $, Router, app) { $(function() { app.router = new Router(); B.history.start(); }); }); Thursday, April 26, 12
  • 24. views display data, announce user interaction, and await further instruction models & collections manage application state and communicate with the server controllers set up views, transport messages from views to models & collections Thursday, April 26, 12
  • 25. app/views/searchForm app/views/recentSearches app/views/results Thursday, April 26, 12
  • 26. app/controllers/search #mainbar #sidebar Thursday, April 26, 12
  • 27. searches collection keeps track of recent search terms search data collection fetches results from the server for a given search term app model keeps track of general application state, including the current search search model for representing individual searches Thursday, April 26, 12
  • 28. app/views/searchForm search controller server search data searches collection app model app/views/recentSearches app/views/results Thursday, April 26, 12
  • 29. $("#searchForm form").submit(function(e) { alert('submit'); e.preventDefault(); var term = $('#searchForm input').val(), req = $.getJSON('http://search.twitter.com/search.json?callba encodeURIComponent(term)); req.then(function(resp) { var resultsHTML = $.map(resp.results, function(r) { return '<li>' + '<p class="tweet">' + r.text + '</p>' + '<p class="username">' + r.from_user + '</p>' + '</li>'; }).join(''); $('#searchResults').html(resultsHTML); }); }); Thursday, April 26, 12
  • 30. app/views/searchForm search controller server search data searches collection app model app/views/recentSearches app/views/results Thursday, April 26, 12
  • 31. prepare : function() { _.bindAll(this, 'release', '_onSearch', '_disable'); }, events : { 'submit .search-form' : '_onSearch' }, _onSearch : function(e) { e.preventDefault(); if (this.disabled) { return; } var term = $.trim(this.$('.js-input').val()); if (!term) { return; } this._disable(); this.trigger('search', term); }, release : function() { this.disabled = false; this.$('.js-submit').removeAttr('disabled'); }, Thursday, April 26, 12
  • 32. searchForm.on('search', update); function update(t) { var term = $.trim(t), existing = searches.where({ term : term }), dfd = $.Deferred(), search; app.set('currentSearch', term); if (term) { if (existing.length) { search = existing[0]; search.update(); } else { search = new Search({ term : term }); searches.add(search); } searchData.fetch({ data : { term : term } }) .then(dfd.resolve, dfd.reject) .always(searchForm.release); app.router.navigate('search/' + term); } else { dfd.resolve(); } return dfd; } Thursday, April 26, 12
  • 33. it("should announce the form submission", function() { var t; sf.on('search', function(term) { t = term; }); el.find('.js-input').val('searchterm'); el.find('.search-form').submit(); expect(t).to.be('searchterm'); }); Thursday, April 26, 12
  • 34. it("should update the page when the search form announces a search", function(done) { var searchFormEl = $('.component.search-form').parent(), searchForm = _.filter(s.views, function(v) { return v.$el[0] === searchFormEl[0]; })[0]; s.searchData.on('change', function() { expect($('.component.results').html()).to.contain('srchr'); expect($('.component.recent-searches').html()).to.contain('srchr'); expect(navigatedTo).to.be('search/srchr'); done(); }); searchForm.trigger('search', 'srchr'); }); Thursday, April 26, 12
  • 35. app/views/searchForm search controller server search data searches collection app model app/views/recentSearches app/views/results Thursday, April 26, 12
  • 36. function update(t) { var term = $.trim(t), existing = searches.where({ term : term }), dfd = $.Deferred(), search; app.set('currentSearch', term); if (term) { if (existing.length) { search = existing[0]; search.update(); } else { search = new Search({ term : term }); searches.add(search); } searchData.fetch({ data : { term : term } }) .then(dfd.resolve, dfd.reject) .always(searchForm.release); app.router.navigate('search/' + term); } else { dfd.resolve(); } return dfd; } Thursday, April 26, 12
  • 37. this.bindTo(this.searchData, 'add change', this._update); this.bindTo(this.searchData, 'fetching', function() { this._empty(); this.reset(); }); Thursday, April 26, 12
  • 39. function update(t) { var term = $.trim(t), existing = searches.where({ term : term }), search; app.set('currentSearch', term); if (existing.length) { search = existing[0]; search.update(); } else { search = new Search({ term : term }); searches.add(search); } searchData.fetch({ data : { term : term } }) .always(searchForm.release); app.router.navigate('search/' + term); } Thursday, April 26, 12
  • 40. describe("#update", function() { it("should update the time", function(done) { var search = new Search(), oldTime = search.get('time'); setTimeout(function() { search.update(); expect(search.get('time')).to.be.greaterThan(oldTime); done(); }, 1000); }); }); Thursday, April 26, 12
  • 41. it("should update when there is a new search", function() { expect(el.html()).not.to.contain('baz'); rs.currentSearch = function() { return 'baz'; }; rs.searches.add({ term : 'baz' }); expect(el.html()).to.contain('baz'); expect(el.find('.active').html()).to.contain('baz'); }); Thursday, April 26, 12
  • 42. memory management requirejs builds for production multi-page apps w/history api Thursday, April 26, 12
  • 43. rmurphey.com • @rmurphey • bocoup.com github.com/rmurphey/srchr-demo Thursday, April 26, 12