Your SlideShare is downloading. ×
0
Beyond the DOM:            Sane Structure for JS Apps            Rebecca Murphey • @rmurphey • BVJS 2012Wednesday, March 7...
github.com/rmurphey/bvjsWednesday, March 7, 12
function ObjInlineDown(e) {                       if( is.ie ) e = event                       if( is.ie && !is.ieMac && e....
Wednesday, March 7, 12
Wednesday, March 7, 12
<!doctype html>                     <html lang="en">                     <head>                       <meta charset="utf-8...
$(#searchInput form).submit(function(e){                       e.preventDefault();                         var term = $(#s...
Wednesday, March 7, 12
// NAVIGATION               function togglePage(section) {                   // if the clicked section is already the curr...
$(#btn-co-complete).live(click, function() {            jobCompleted = true;            $.mobile.changePage(#page-clockout...
search input   $(#searchInput form).submit(function(e){                                          e.preventDefault();      ...
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="...
<script data-main="app/config" src="/assets/js/libs/require.js"></script>Wednesday, March 7, 12
require.config({                       deps: ["main"],                         paths: {                           // JavaS...
define([                       "components/page",                       "components/search/input",                       "...
// NAVIGATION               function togglePage(section) {                   // if the clicked section is already the curr...
component              controller                         component                                                 servic...
component            controller                         component                                               service   ...
component              controller                         component                                                 servic...
Wednesday, March 7, 12
controller                         twitter searchWednesday, March 7, 12
components display data, observe input, and               broadcast messages that controllers can react               to; ...
define([                 "components/base"               ], function(Component) {                 return Component({      ...
<form>                 <input placeholder="enter your search term">                 <button>submit</button>               ...
controllers set up components and broker               communications between them, eliminating               the need for...
<!doctype html>                     <html lang="en">                     <head>                       <meta charset="utf-8...
var Router = Backbone.Router.extend({                      routes: {                         "": "twitter",               ...
define([                 "components/page", "components/search/input",                 "components/search/results", "servi...
services expose an API for controllers               to interact with dataWednesday, March 7, 12
define([                 "use!backbone"               ], function(Backbone) {                 var TwitterResult = Backbone...
“Writing to be read means writing code ... with               the idea that someone else will read it. is               f...
github.com/rmurphey/bvjsWednesday, March 7, 12
rmurphey.com • @rmurpheyWednesday, March 7, 12
Upcoming SlideShare
Loading in...5
×

BVJS

4,209

Published on

Transcript of "BVJS"

  1. 1. Beyond the DOM: Sane Structure for JS Apps Rebecca Murphey • @rmurphey • BVJS 2012Wednesday, March 7, 12
  2. 2. github.com/rmurphey/bvjsWednesday, March 7, 12
  3. 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
  4. 4. Wednesday, March 7, 12
  5. 5. Wednesday, March 7, 12
  6. 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. 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
  8. 8. Wednesday, March 7, 12
  9. 9. // NAVIGATION function togglePage(section) { // if the clicked section is already the current section AND were 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 were NOT in full page mode // then lets 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. 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. 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
  12. 12. Wednesday, March 7, 12
  13. 13. Wednesday, March 7, 12
  14. 14. Wednesday, March 7, 12
  15. 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
  16. 16. <script data-main="app/config" src="/assets/js/libs/require.js"></script>Wednesday, March 7, 12
  17. 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. 18. define([ "components/page", "components/search/input", "components/search/results", ], function(Page, SearchInput, SearchResults) { return { // ... }; });Wednesday, March 7, 12
  19. 19. // NAVIGATION function togglePage(section) { // if the clicked section is already the current section AND were 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 were NOT in full page mode // then lets 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. 20. component controller component service components display data, observe input, and broadcast messages that controllers can react to; may also provide an API for updatingWednesday, March 7, 12
  21. 21. component controller component service controllers set up components and broker communications between them, eliminating the need for direct communicationWednesday, March 7, 12
  22. 22. component controller component service services expose an API for controllers to retrieve and persist dataWednesday, March 7, 12
  23. 23. Wednesday, March 7, 12
  24. 24. controller twitter searchWednesday, March 7, 12
  25. 25. components display data, observe input, and broadcast messages that controllers can react to; may also provide an API for updatingWednesday, March 7, 12
  26. 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. 27. <form> <input placeholder="enter your search term"> <button>submit</button> </form>Wednesday, March 7, 12
  28. 28. controllers set up components and broker communications between them, eliminating the need for direct communicationWednesday, March 7, 12
  29. 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. 30. var Router = Backbone.Router.extend({ routes: { "": "twitter", ":hash": "twitter" }, twitter : function(hash) { SearchController.init(); } });Wednesday, March 7, 12
  31. 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. 32. services expose an API for controllers to interact with dataWednesday, March 7, 12
  33. 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. 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
  35. 35. github.com/rmurphey/bvjsWednesday, March 7, 12
  36. 36. rmurphey.com • @rmurpheyWednesday, March 7, 12
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×