SlideShare uma empresa Scribd logo
1 de 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

Mais conteúdo relacionado

Mais procurados

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
 

Mais procurados (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
 

Semelhante a 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
 

Semelhante a 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
 

Mais de Rebecca Murphey

Mais 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
 

Último

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
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
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
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Principled Technologies
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
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
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
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
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 

Último (20)

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
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
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)
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
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
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
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
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 

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