SlideShare a Scribd company logo
Beyond the DOM:
            Sane Structure for JS Apps
            Rebecca Murphey • @rmurphey • BVJS 2012

Wednesday, March 7, 12
github.com/rmurphey/bvjs




Wednesday, March 7, 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()
                     }




Wednesday, March 7, 12
Wednesday, March 7, 12
Wednesday, March 7, 12
<!doctype html>
                     <html lang="en">
                     <head>
                       <meta charset="utf-8">
                       <title>Twitter Search</title>
                       <link rel="stylesheet" href="/assets/css/index.css">
                     </head>

                     <body>
                       <h1>Twitter Search</h1>
                       <div id="searchInput">
                         <form>
                            <input placeholder="enter your search term">
                            <button>submit</button>
                         </form>
                       </div>
                       <ul id="searchResults"></ul>

                       <script src="/assets/js/libs/jquery.js"></script>
                       <script src="/assets/js/app.js"></script>
                     </body>
                     </html>




Wednesday, March 7, 12
$('#searchInput form').submit(function(e){
                       e.preventDefault();

                         var term = $('#searchInput input').val(),
                             req = $.getJSON('http://search.twitter.com/search.json?callback=?&q=' +
                                   escape(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);
                       });
                     });




Wednesday, March 7, 12
Wednesday, March 7, 12
// NAVIGATION
               function togglePage(section) {
                   // if the clicked section is already the current section AND we're in full page mode
                   // minimize the current tab
                   if (jQuery('#md_tab_'+ section).hasClass('current') && jQuery('#md_tab_'+ section + ' 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(){
                                            var t = this.title || this.name || null;
                                            var a = this.href || this.alt;
                                            var g = this.rel || false;
                                            tb_show(t,a,g);
                                            this.blur();
                                            return false;
                                        });
Wednesday, March 7, 12              // ACCORDION
$('#btn-co-complete').live('click', function() {
            jobCompleted = true;
            $.mobile.changePage('#page-clockout-deficiency', {changeHash: false});
        });

        $('#btn-co-nocomplete').live('click', function() {
            jobCompleted = false;
            $.mobile.changePage('#page-clockout-deficiency', {changeHash: false});
        });

        $('#btn-co-nodef').live('click', function() {
            clockOut(activeJob, { completed:jobCompleted }, DW_JOB_COMPLETED);
        });

        $('#btn-co-otherdef').live('click', function() {
            $.mobile.changePage('#page-clockout-redtag', {changeHash: false});
        });

        $('#btn-co-redtag').live('click', function() {
            clockOut(activeJob, { completed:jobCompleted, redTag:true }, DW_JOB_FOLLOWUP)
        });

        $('#btn-co-noredtag').live('click', function() {
            $('#page-clockout-resolve').page();
            $.mobile.changePage('#page-clockout-resolve', {changeHash: false});
        });

             $('#btn-clockout-resolve').live('click', function() {
                       switch ($('#page-clockout-resolve :checked').val()) {
                       case 'return':
Wednesday, March 7, 12     clockOut(activeJob, { completed:false }, DW_JOB_RETURN);
search input   $('#searchInput form').submit(function(e){
                                          e.preventDefault();

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

                                          req.then(function(resp) {
                         search data        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);
                     search results       });
                                        });




Wednesday, March 7, 12
Wednesday, March 7, 12
Wednesday, March 7, 12
Wednesday, March 7, 12
<script   type="text/javascript"   src="http://static.a2cdn.net/misc/jquery.js?9"></script>
               <script   type="text/javascript"   src="http://static.a2cdn.net/misc/drupal.js?9"></script>
               <script   type="text/javascript"   src="/google_analytics/googleanalytics.js?9"></script>
               <script   type="text/javascript"   src="/mollom/mollom.js?9"></script>
               <script   type="text/javascript"   src="/js/jquery-1.4.2.min.js?9"></script>
               <script   type="text/javascript"   src="/js/jquery-ui-1.8.4.custom.min.js?9"></script>
               <script   type="text/javascript"   src="/js/jquery.infieldlabel.min.js?9"></script>
               <script   type="text/javascript"   src="/js/jquery.nivo.slider.js?9"></script>
               <script   type="text/javascript"   src="/js/validations.js?9"></script>
               <script   type="text/javascript"   src="/js/site.js?9"></script>
               <script   type="text/javascript"   src="/js/noconflict.js?9"></script>




Wednesday, March 7, 12
<script data-main="app/config" src="/assets/js/libs/require.js"></script>




Wednesday, March 7, 12
require.config({
                       deps: ["main"],

                         paths: {
                           // JavaScript folders
                           libs: "../assets/js/libs",
                           plugins: "../assets/js/plugins",

                           // Libraries
                           jquery: "../assets/js/libs/jquery",
                           underscore: "../assets/js/libs/underscore",
                           backbone: "../assets/js/libs/backbone"
                       }
                     });




Wednesday, March 7, 12
define([
                       "components/page",
                       "components/search/input",
                       "components/search/results",
                     ], function(Page, SearchInput, SearchResults) {
                       return {
                          // ...
                       };
                     });




Wednesday, March 7, 12
// NAVIGATION
               function togglePage(section) {
                   // if the clicked section is already the current section AND we're in full page mode
                   // minimize the current tab
                   if (jQuery('#md_tab_'+ section).hasClass('current') && jQuery('#md_tab_'+ section + ' 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(){
                                            var t = this.title || this.name || null;
                                            var a = this.href || this.alt;
                                            var g = this.rel || false;
                                            tb_show(t,a,g);
                                            this.blur();
                                            return false;
                                        });
                                    // ACCORDION
                                    jQuery('div.applemenu div.submenu').hide();
                                    jQuery('div.applemenu div.silverheader < a').click(
Wednesday, March 7, 12                  function(){
component              controller


                         component




                                                 service



               components display data, observe input, and
               broadcast messages that controllers can react
               to; may also provide an API for updating


Wednesday, March 7, 12
component            controller


                         component




                                               service



               controllers set up components and broker
               communications between them, eliminating
               the need for direct communication


Wednesday, March 7, 12
component              controller


                         component




                                                 service




               services expose an API for controllers
               to retrieve and persist data


Wednesday, March 7, 12
Wednesday, March 7, 12
controller




                         twitter search




Wednesday, March 7, 12
components display data, observe input, and
               broadcast messages that controllers can react
               to; may also provide an API for updating




Wednesday, March 7, 12
define([
                 "components/base"
               ], function(Component) {
                 return Component({
                   template : "app/templates/search/input.html",
                   className : 'search-input',

                         events : {
                            "submit form"   :   "_onSubmit"
                         },

                   _onSubmit : function(e) {
                     e.preventDefault();
                     var term = $.trim(this.$el.find('input')[0].value);
                     if (!term) { return; }
                     this.trigger('search', term);
                   }
                 });
               });




Wednesday, March 7, 12
<form>
                 <input placeholder="enter your search term">
                 <button>submit</button>
               </form>




Wednesday, March 7, 12
controllers set up components and broker
               communications between them, eliminating
               the need for direct communication




Wednesday, March 7, 12
<!doctype html>
                     <html lang="en">
                     <head>
                       <meta charset="utf-8">
                       <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
                       <meta name="viewport" content="width=device-width,initial-scale=1">

                         <title>Searchr</title>

                       <!-- Application styles -->
                       <link rel="stylesheet" href="/assets/css/index.css">
                     </head>

                     <body>
                       <!-- Main container -->
                       <div role="main" id="main"></div>

                       <!-- Application source -->
                       <script data-main="app/config" src="/assets/js/libs/require.js"></
                     script>
                     </body>
                     </html>




Wednesday, March 7, 12
var Router = Backbone.Router.extend({
                      routes: {
                         "": "twitter",
                         ":hash": "twitter"
                      },

                      twitter : function(hash) {
                        SearchController.init();
                      }
                    });




Wednesday, March 7, 12
define([
                 "components/page", "components/search/input",
                 "components/search/results", "services/twitter"
               ], function(Page, SearchInput, SearchResults, twitterService) {
                 return {
                   init : function() {
                     this.page = new Page({ template : 'app/templates/pages/search.html' });
                     this.page.render().then(_.bind(this.setupPage, this));
                   },

                         setupPage : function() {
                           var p = this.page;
                           this.searchInput = p.place(new SearchInput(), 'searchInput');
                           this.searchResults = p.place(new SearchResults(), 'searchResults');
                           this.searchInput.on('search', _.bind(this.handleSearch, this));
                         },

                         handleSearch : function(term) {
                            twitterService.query(term).then(_.bind(this.showResults, this));
                         },

                         showResults : function(results) {
                           this.searchResults.show(results);
                         }
                 };
               });




Wednesday, March 7, 12
services expose an API for controllers
               to interact with data




Wednesday, March 7, 12
define([
                 "use!backbone"
               ], function(Backbone) {
                 var TwitterResult = Backbone.Model.extend({
                   // ...
                 });

                   var TwitterResults = Backbone.Collection.extend({
                     type : 'twitter', model : TwitterResult
                   });

                   return {
                     query : function(term) {
                       var req = $.getJSON('http://search.twitter.com/search.json?callback=?&q=' +
                            escape(term)),
                            dfd = $.Deferred();

                         req.then(function(resp) {
                           dfd.resolve(new TwitterResults(resp.results));
                         });

                         return dfd.promise();
                   }
                 };
               });




Wednesday, March 7, 12
“Writing to be read means writing code ... with
               the idea that someone else will read it. is
               fact alone will make you edit and think of better
               ways to solve the problem you have at hand.”
                                       Stoyan Stefanov, “JavaScript Patterns”



Wednesday, March 7, 12
github.com/rmurphey/bvjs




Wednesday, March 7, 12
rmurphey.com • @rmurphey




Wednesday, March 7, 12

More Related Content

PDF
Beyond the DOM: Sane Structure for JS Apps
Rebecca Murphey
 
PDF
Delivering a Responsive UI
Rebecca Murphey
 
PDF
Functionality Focused Code Organization
Rebecca Murphey
 
KEY
Jquery Fundamentals
Rebecca Murphey
 
PDF
Building Large jQuery Applications
Rebecca Murphey
 
PDF
Using Templates to Achieve Awesomer Architecture
Garann Means
 
PDF
Cleaner, Leaner, Meaner: Refactoring your jQuery
Rebecca Murphey
 
PDF
Mulberry: A Mobile App Development Toolkit
Rebecca Murphey
 
Beyond the DOM: Sane Structure for JS Apps
Rebecca Murphey
 
Delivering a Responsive UI
Rebecca Murphey
 
Functionality Focused Code Organization
Rebecca Murphey
 
Jquery Fundamentals
Rebecca Murphey
 
Building Large jQuery Applications
Rebecca Murphey
 
Using Templates to Achieve Awesomer Architecture
Garann Means
 
Cleaner, Leaner, Meaner: Refactoring your jQuery
Rebecca Murphey
 
Mulberry: A Mobile App Development Toolkit
Rebecca Murphey
 

What's hot (20)

KEY
jQuery Namespace Pattern
Diego Fleury
 
PPTX
jQuery Data Manipulate API - A source code dissecting journey
Huiyi Yan
 
PDF
Dojo Confessions
Rebecca Murphey
 
PDF
A New Baseline for Front-End Devs
Rebecca Murphey
 
PDF
Intro to Advanced JavaScript
ryanstout
 
PPTX
Bacbkone js
Артём Курапов
 
PDF
Writing Maintainable JavaScript
Andrew Dupont
 
PDF
Using Objects to Organize your jQuery Code
Rebecca Murphey
 
PDF
Doctrine For Beginners
Jonathan Wage
 
PPT
Kick start with j query
Md. Ziaul Haq
 
PDF
How Kris Writes Symfony Apps
Kris Wallsmith
 
KEY
Advanced jQuery
sergioafp
 
PPTX
jQuery
Jay Poojara
 
PPT
jQuery
Niladri Karmakar
 
PDF
jQuery secrets
Bastian Feder
 
PDF
Jqeury ajax plugins
Inbal Geffen
 
PDF
Matters of State
Kris Wallsmith
 
PPTX
JQuery
SelmanJagxhiu
 
PDF
Design how your objects talk through mocking
Konstantin Kudryashov
 
PDF
Command-Oriented Architecture
Luiz Messias
 
jQuery Namespace Pattern
Diego Fleury
 
jQuery Data Manipulate API - A source code dissecting journey
Huiyi Yan
 
Dojo Confessions
Rebecca Murphey
 
A New Baseline for Front-End Devs
Rebecca Murphey
 
Intro to Advanced JavaScript
ryanstout
 
Writing Maintainable JavaScript
Andrew Dupont
 
Using Objects to Organize your jQuery Code
Rebecca Murphey
 
Doctrine For Beginners
Jonathan Wage
 
Kick start with j query
Md. Ziaul Haq
 
How Kris Writes Symfony Apps
Kris Wallsmith
 
Advanced jQuery
sergioafp
 
jQuery
Jay Poojara
 
jQuery secrets
Bastian Feder
 
Jqeury ajax plugins
Inbal Geffen
 
Matters of State
Kris Wallsmith
 
Design how your objects talk through mocking
Konstantin Kudryashov
 
Command-Oriented Architecture
Luiz Messias
 
Ad

Similar to BVJS (20)

PDF
DOM Scripting Toolkit - jQuery
Remy Sharp
 
PDF
HTML5: Building the Next Generation of Web Applications
Chrome Developer Relations
 
PPTX
Toronto User groups workshop - 2013-03-10 - HTML5 & Windows 8, friends with b...
Frédéric Harper
 
PPTX
Lecture-5.pptx
vishal choudhary
 
KEY
Google
soon
 
PPTX
SEF2013 - A jQuery Primer for SharePoint
Marc D Anderson
 
PDF
jQuery Introduction
Arwid Bancewicz
 
PDF
Using jQuery to Extend CSS
Chris Coyier
 
PDF
Remy Sharp The DOM scripting toolkit jQuery
deimos
 
PPT
Jquery 5
Manish Kumar Singh
 
KEY
An introduction to jQuery
James Wragg
 
PDF
JS Single-Page Web App Essentials
Sergey Bolshchikov
 
PDF
Javascript in Plone
Steve McMahon
 
PDF
The Dom Scripting Toolkit J Query
QConLondon2008
 
PPTX
SPSNH 2014 - The SharePoint & jQueryGuide
Mark Rackley
 
PPTX
Customizing the SharePoint 2013 user interface with JavaScript - Chris OBrien
Chris O'Brien
 
PDF
Organizing Code with JavascriptMVC
Thomas Reynolds
 
PPTX
Google I/O 2012 - Protecting your user experience while integrating 3rd party...
Patrick Meenan
 
PDF
jQuery Rescue Adventure
Allegient
 
PDF
Html5 apis
Ynon Perek
 
DOM Scripting Toolkit - jQuery
Remy Sharp
 
HTML5: Building the Next Generation of Web Applications
Chrome Developer Relations
 
Toronto User groups workshop - 2013-03-10 - HTML5 & Windows 8, friends with b...
Frédéric Harper
 
Lecture-5.pptx
vishal choudhary
 
Google
soon
 
SEF2013 - A jQuery Primer for SharePoint
Marc D Anderson
 
jQuery Introduction
Arwid Bancewicz
 
Using jQuery to Extend CSS
Chris Coyier
 
Remy Sharp The DOM scripting toolkit jQuery
deimos
 
An introduction to jQuery
James Wragg
 
JS Single-Page Web App Essentials
Sergey Bolshchikov
 
Javascript in Plone
Steve McMahon
 
The Dom Scripting Toolkit J Query
QConLondon2008
 
SPSNH 2014 - The SharePoint & jQueryGuide
Mark Rackley
 
Customizing the SharePoint 2013 user interface with JavaScript - Chris OBrien
Chris O'Brien
 
Organizing Code with JavascriptMVC
Thomas Reynolds
 
Google I/O 2012 - Protecting your user experience while integrating 3rd party...
Patrick Meenan
 
jQuery Rescue Adventure
Allegient
 
Html5 apis
Ynon Perek
 
Ad

More from Rebecca Murphey (7)

PDF
Getting Started with Mulberry
Rebecca Murphey
 
PDF
Introducing Mulberry
Rebecca Murphey
 
PDF
DojoConf: Building Large Apps
Rebecca Murphey
 
PDF
Lessons from-a-rewrite-gotham
Rebecca Murphey
 
PDF
Lessons from a Rewrite
Rebecca Murphey
 
PDF
Modern JavaScript
Rebecca Murphey
 
PDF
The jQuery Divide
Rebecca Murphey
 
Getting Started with Mulberry
Rebecca Murphey
 
Introducing Mulberry
Rebecca Murphey
 
DojoConf: Building Large Apps
Rebecca Murphey
 
Lessons from-a-rewrite-gotham
Rebecca Murphey
 
Lessons from a Rewrite
Rebecca Murphey
 
Modern JavaScript
Rebecca Murphey
 
The jQuery Divide
Rebecca Murphey
 

Recently uploaded (20)

PPTX
AI and Robotics for Human Well-being.pptx
JAYMIN SUTHAR
 
PDF
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
PDF
The Future of Artificial Intelligence (AI)
Mukul
 
PPTX
Dev Dives: Automate, test, and deploy in one place—with Unified Developer Exp...
AndreeaTom
 
PDF
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
PDF
Oracle AI Vector Search- Getting Started and what's new in 2025- AIOUG Yatra ...
Sandesh Rao
 
PDF
The Future of Mobile Is Context-Aware—Are You Ready?
iProgrammer Solutions Private Limited
 
PPTX
Introduction to Flutter by Ayush Desai.pptx
ayushdesai204
 
PPTX
The-Ethical-Hackers-Imperative-Safeguarding-the-Digital-Frontier.pptx
sujalchauhan1305
 
PDF
Accelerating Oracle Database 23ai Troubleshooting with Oracle AHF Fleet Insig...
Sandesh Rao
 
PDF
Security features in Dell, HP, and Lenovo PC systems: A research-based compar...
Principled Technologies
 
PDF
Software Development Methodologies in 2025
KodekX
 
PDF
AI-Cloud-Business-Management-Platforms-The-Key-to-Efficiency-Growth.pdf
Artjoker Software Development Company
 
PPTX
OA presentation.pptx OA presentation.pptx
pateldhruv002338
 
PDF
SparkLabs Primer on Artificial Intelligence 2025
SparkLabs Group
 
PDF
Get More from Fiori Automation - What’s New, What Works, and What’s Next.pdf
Precisely
 
PDF
Presentation about Hardware and Software in Computer
snehamodhawadiya
 
PPTX
New ThousandEyes Product Innovations: Cisco Live June 2025
ThousandEyes
 
PPTX
AI in Daily Life: How Artificial Intelligence Helps Us Every Day
vanshrpatil7
 
PDF
Economic Impact of Data Centres to the Malaysian Economy
flintglobalapac
 
AI and Robotics for Human Well-being.pptx
JAYMIN SUTHAR
 
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
The Future of Artificial Intelligence (AI)
Mukul
 
Dev Dives: Automate, test, and deploy in one place—with Unified Developer Exp...
AndreeaTom
 
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
Oracle AI Vector Search- Getting Started and what's new in 2025- AIOUG Yatra ...
Sandesh Rao
 
The Future of Mobile Is Context-Aware—Are You Ready?
iProgrammer Solutions Private Limited
 
Introduction to Flutter by Ayush Desai.pptx
ayushdesai204
 
The-Ethical-Hackers-Imperative-Safeguarding-the-Digital-Frontier.pptx
sujalchauhan1305
 
Accelerating Oracle Database 23ai Troubleshooting with Oracle AHF Fleet Insig...
Sandesh Rao
 
Security features in Dell, HP, and Lenovo PC systems: A research-based compar...
Principled Technologies
 
Software Development Methodologies in 2025
KodekX
 
AI-Cloud-Business-Management-Platforms-The-Key-to-Efficiency-Growth.pdf
Artjoker Software Development Company
 
OA presentation.pptx OA presentation.pptx
pateldhruv002338
 
SparkLabs Primer on Artificial Intelligence 2025
SparkLabs Group
 
Get More from Fiori Automation - What’s New, What Works, and What’s Next.pdf
Precisely
 
Presentation about Hardware and Software in Computer
snehamodhawadiya
 
New ThousandEyes Product Innovations: Cisco Live June 2025
ThousandEyes
 
AI in Daily Life: How Artificial Intelligence Helps Us Every Day
vanshrpatil7
 
Economic Impact of Data Centres to the Malaysian Economy
flintglobalapac
 

BVJS

  • 1. Beyond the DOM: Sane Structure for JS Apps Rebecca Murphey • @rmurphey • BVJS 2012 Wednesday, March 7, 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() } Wednesday, March 7, 12
  • 6. <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Twitter Search</title> <link rel="stylesheet" href="/assets/css/index.css"> </head> <body> <h1>Twitter Search</h1> <div id="searchInput"> <form> <input placeholder="enter your search term"> <button>submit</button> </form> </div> <ul id="searchResults"></ul> <script src="/assets/js/libs/jquery.js"></script> <script src="/assets/js/app.js"></script> </body> </html> Wednesday, March 7, 12
  • 7. $('#searchInput form').submit(function(e){ e.preventDefault(); var term = $('#searchInput input').val(), req = $.getJSON('http://search.twitter.com/search.json?callback=?&q=' + escape(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); }); }); Wednesday, March 7, 12
  • 9. // NAVIGATION function togglePage(section) { // if the clicked section is already the current section AND we're in full page mode // minimize the current tab if (jQuery('#md_tab_'+ section).hasClass('current') && jQuery('#md_tab_'+ section + ' 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(){ var t = this.title || this.name || null; var a = this.href || this.alt; var g = this.rel || false; tb_show(t,a,g); this.blur(); return false; }); Wednesday, March 7, 12 // ACCORDION
  • 10. $('#btn-co-complete').live('click', function() { jobCompleted = true; $.mobile.changePage('#page-clockout-deficiency', {changeHash: false}); }); $('#btn-co-nocomplete').live('click', function() { jobCompleted = false; $.mobile.changePage('#page-clockout-deficiency', {changeHash: false}); }); $('#btn-co-nodef').live('click', function() { clockOut(activeJob, { completed:jobCompleted }, DW_JOB_COMPLETED); }); $('#btn-co-otherdef').live('click', function() { $.mobile.changePage('#page-clockout-redtag', {changeHash: false}); }); $('#btn-co-redtag').live('click', function() { clockOut(activeJob, { completed:jobCompleted, redTag:true }, DW_JOB_FOLLOWUP) }); $('#btn-co-noredtag').live('click', function() { $('#page-clockout-resolve').page(); $.mobile.changePage('#page-clockout-resolve', {changeHash: false}); }); $('#btn-clockout-resolve').live('click', function() { switch ($('#page-clockout-resolve :checked').val()) { case 'return': Wednesday, March 7, 12 clockOut(activeJob, { completed:false }, DW_JOB_RETURN);
  • 11. search input $('#searchInput form').submit(function(e){ e.preventDefault(); var term = $('#searchInput input').val(), req = $.getJSON('http://search.twitter.com/searc escape(term)); req.then(function(resp) { search data 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); search results }); }); Wednesday, March 7, 12
  • 15. <script type="text/javascript" src="http://static.a2cdn.net/misc/jquery.js?9"></script> <script type="text/javascript" src="http://static.a2cdn.net/misc/drupal.js?9"></script> <script type="text/javascript" src="/google_analytics/googleanalytics.js?9"></script> <script type="text/javascript" src="/mollom/mollom.js?9"></script> <script type="text/javascript" src="/js/jquery-1.4.2.min.js?9"></script> <script type="text/javascript" src="/js/jquery-ui-1.8.4.custom.min.js?9"></script> <script type="text/javascript" src="/js/jquery.infieldlabel.min.js?9"></script> <script type="text/javascript" src="/js/jquery.nivo.slider.js?9"></script> <script type="text/javascript" src="/js/validations.js?9"></script> <script type="text/javascript" src="/js/site.js?9"></script> <script type="text/javascript" src="/js/noconflict.js?9"></script> Wednesday, March 7, 12
  • 17. require.config({ deps: ["main"], paths: { // JavaScript folders libs: "../assets/js/libs", plugins: "../assets/js/plugins", // Libraries jquery: "../assets/js/libs/jquery", underscore: "../assets/js/libs/underscore", backbone: "../assets/js/libs/backbone" } }); Wednesday, March 7, 12
  • 18. define([ "components/page", "components/search/input", "components/search/results", ], function(Page, SearchInput, SearchResults) { return { // ... }; }); Wednesday, March 7, 12
  • 19. // NAVIGATION function togglePage(section) { // if the clicked section is already the current section AND we're in full page mode // minimize the current tab if (jQuery('#md_tab_'+ section).hasClass('current') && jQuery('#md_tab_'+ section + ' 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(){ var t = this.title || this.name || null; var a = this.href || this.alt; var g = this.rel || false; tb_show(t,a,g); this.blur(); return false; }); // ACCORDION jQuery('div.applemenu div.submenu').hide(); jQuery('div.applemenu div.silverheader < a').click( Wednesday, March 7, 12 function(){
  • 20. component controller component service components display data, observe input, and broadcast messages that controllers can react to; may also provide an API for updating Wednesday, March 7, 12
  • 21. component controller component service controllers set up components and broker communications between them, eliminating the need for direct communication Wednesday, March 7, 12
  • 22. component controller component service services expose an API for controllers to retrieve and persist data Wednesday, March 7, 12
  • 24. controller twitter search Wednesday, March 7, 12
  • 25. components display data, observe input, and broadcast messages that controllers can react to; may also provide an API for updating Wednesday, March 7, 12
  • 26. define([ "components/base" ], function(Component) { return Component({ template : "app/templates/search/input.html", className : 'search-input', events : { "submit form" : "_onSubmit" }, _onSubmit : function(e) { e.preventDefault(); var term = $.trim(this.$el.find('input')[0].value); if (!term) { return; } this.trigger('search', term); } }); }); Wednesday, March 7, 12
  • 27. <form> <input placeholder="enter your search term"> <button>submit</button> </form> Wednesday, March 7, 12
  • 28. controllers set up components and broker communications between them, eliminating the need for direct communication Wednesday, March 7, 12
  • 29. <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Searchr</title> <!-- Application styles --> <link rel="stylesheet" href="/assets/css/index.css"> </head> <body> <!-- Main container --> <div role="main" id="main"></div> <!-- Application source --> <script data-main="app/config" src="/assets/js/libs/require.js"></ script> </body> </html> Wednesday, March 7, 12
  • 30. var Router = Backbone.Router.extend({ routes: { "": "twitter", ":hash": "twitter" }, twitter : function(hash) { SearchController.init(); } }); Wednesday, March 7, 12
  • 31. define([ "components/page", "components/search/input", "components/search/results", "services/twitter" ], function(Page, SearchInput, SearchResults, twitterService) { return { init : function() { this.page = new Page({ template : 'app/templates/pages/search.html' }); this.page.render().then(_.bind(this.setupPage, this)); }, setupPage : function() { var p = this.page; this.searchInput = p.place(new SearchInput(), 'searchInput'); this.searchResults = p.place(new SearchResults(), 'searchResults'); this.searchInput.on('search', _.bind(this.handleSearch, this)); }, handleSearch : function(term) { twitterService.query(term).then(_.bind(this.showResults, this)); }, showResults : function(results) { this.searchResults.show(results); } }; }); Wednesday, March 7, 12
  • 32. services expose an API for controllers to interact with data Wednesday, March 7, 12
  • 33. define([ "use!backbone" ], function(Backbone) { var TwitterResult = Backbone.Model.extend({ // ... }); var TwitterResults = Backbone.Collection.extend({ type : 'twitter', model : TwitterResult }); return { query : function(term) { var req = $.getJSON('http://search.twitter.com/search.json?callback=?&q=' + escape(term)), dfd = $.Deferred(); req.then(function(resp) { dfd.resolve(new TwitterResults(resp.results)); }); return dfd.promise(); } }; }); Wednesday, March 7, 12
  • 34. “Writing to be read means writing code ... with the idea that someone else will read it. is fact alone will make you edit and think of better ways to solve the problem you have at hand.” Stoyan Stefanov, “JavaScript Patterns” Wednesday, March 7, 12