SlideShare a Scribd company logo
1 of 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

More Related Content

What's hot

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
 

What's hot (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
 

Similar to 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
 

Similar to 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
 

More from Rebecca Murphey

More from 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
 

Recently uploaded

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
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
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
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
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
 
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
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
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
 
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
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
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
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 

Recently uploaded (20)

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
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
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...
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
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
 
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
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
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
 
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...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
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
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 

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