• Save
Beyond the DOM: Sane Structure for JS Apps
Upcoming SlideShare
Loading in...5
×
 

Beyond the DOM: Sane Structure for JS Apps

on

  • 3,075 views

Delivered at 2012 FrontTrends in Warsaw.

Delivered at 2012 FrontTrends in Warsaw.

Statistics

Views

Total Views
3,075
Views on SlideShare
2,915
Embed Views
160

Actions

Likes
14
Downloads
0
Comments
0

2 Embeds 160

http://coderwall.com 159
https://twitter.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Beyond the DOM: Sane Structure for JS Apps Beyond the DOM: Sane Structure for JS Apps Presentation Transcript

    • Beyond the DOM: Sane Structure for JS Apps Rebecca Murphey • @rmurphey • FrontTrends 2012Thursday, April 26, 12
    • rmurphey.com • @rmurphey • bocoup.comThursday, 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 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(){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 & collectionsThursday, April 26, 12
    • app/views/searchForm app/views/recentSearches app/views/resultsThursday, April 26, 12
    • app/controllers/search #mainbar #sidebarThursday, 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 searchesThursday, April 26, 12
    • app/views/searchForm search controller server search data searches collection app model app/views/recentSearches app/views/resultsThursday, 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/resultsThursday, 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/resultsThursday, 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 apiThursday, April 26, 12
    • rmurphey.com • @rmurphey • bocoup.com github.com/rmurphey/srchr-demoThursday, April 26, 12