SlideShare ist ein Scribd-Unternehmen logo
1 von 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

Weitere ähnliche Inhalte

Was ist angesagt?

Jqeury ajax plugins
Jqeury ajax pluginsJqeury ajax plugins
Jqeury ajax plugins
Inbal Geffen
 
Cleaner, Leaner, Meaner: Refactoring your jQuery
Cleaner, Leaner, Meaner: Refactoring your jQueryCleaner, Leaner, Meaner: Refactoring your jQuery
Cleaner, Leaner, Meaner: Refactoring your jQuery
Rebecca Murphey
 

Was ist angesagt? (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
 

Ähnlich wie Beyond the DOM: Sane Structure for JS Apps

[removed] $file, removeRemove}, list #su.docx
[removed] $file, removeRemove}, list #su.docx[removed] $file, removeRemove}, list #su.docx
[removed] $file, removeRemove}, list #su.docx
gerardkortney
 
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
smueller_sandsmedia
 
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
Jarod Ferguson
 
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docxsrcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
srcArtifact.javasrcArtifact.javaclassArtifactextendsCave{pub.docx
whitneyleman54422
 

Ähnlich wie 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
 

Mehr von 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
 

Kürzlich hochgeladen

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 

Kürzlich hochgeladen (20)

Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
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
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
 
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
 
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
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 

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