From d48da5e1d1855f5bc84df1f9a74a7f019bae2463 Mon Sep 17 00:00:00 2001 From: Pascal Hartig Date: Mon, 26 Aug 2013 15:49:52 +0200 Subject: [PATCH] Add durandal dependency example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Squashed commit of the following: commit 3527bd3bfb1677b07b5b33d5875f9d33476922b2 Author: abhinav Date: Mon Aug 26 16:32:40 2013 +0530 added space commit 6028ac961956b8e763898161ff5889d6f74c93ae Author: abhinav Date: Mon Aug 26 16:09:04 2013 +0530 indentation and spacing for comments. Removed chrome = 1 commit 8d14fad78e4559cd3dc0f02693c5b38269e616f4 Author: abhinav Date: Thu Aug 22 12:48:08 2013 +0530 Added cancel functionality on escape key by using a temporary shadow observable which updates the title only on a non-escape blur from the text box. commit 33d6d68d5543a811301b2c5be95ebc7fd8d412a6 Author: abhinav Date: Wed Aug 21 19:32:54 2013 +0530 the editing property is removed from the todo object and moved into the root. Also - rolled back the silliness in the last edit. commit 37eec81f26965cfca7f607e8f9fbbf4bd1b57af2 Author: abhinav Date: Wed Aug 21 18:50:49 2013 +0530 removed the durandal.css style sheet altogether commit 1b2df765977f493ccbde1470712443d164662042 Author: abhinav Date: Wed Aug 21 18:43:43 2013 +0530 created a shadow field for title , so that if the user closes the page while editing, the title is not affected, only the shadow is change which gets discarded. commit 71877d509bea74cd4f268c78d8e61ddd59149c1b Author: abhinav Date: Fri Aug 9 16:44:16 2013 +0530 Now trimming on edit as well. commit 0ccbc8c4d8af7ab25d403b03f3cf68c426823832 Author: abhinav Date: Fri Aug 9 16:15:37 2013 +0530 added back modalDialog.js commit 4f655ec271b15eff4a66489072ae73aee3e576f2 Author: abhinav Date: Fri Aug 9 16:15:12 2013 +0530 sending filter parameter via shared shell commit 33fd5cf0f0c909e3749f84bec85d1250c58608e9 Author: abhinav Date: Fri Aug 9 16:14:38 2013 +0530 wrapped in anonymous closure commit 6d8af2c79046a675244ed3df4c316caab43ae35f Author: abhinav Date: Fri Aug 9 16:01:00 2013 +0530 using the url routing logic to control the tasks filter. commit 29c6dcfc3cdefeded4a47ee9e00fde72eabbff7c Author: abhinav Date: Fri Aug 9 16:00:17 2013 +0530 Removed the loading animation commit c32cd033ef2454e90849fccf6a7b97215c89f94b Author: abhinav Date: Fri Aug 9 15:15:20 2013 +0530 converted indentation to tabs across js and html commit 50fe84828d8493dabb848652fadad89e3697bed5 Author: abhinav Date: Fri Aug 9 15:08:21 2013 +0530 removed unused files from durandal library set. commit 08cf6f9010a1bbd20446653a8c84af9208cf8499 Author: abhinav Date: Thu Aug 8 16:20:10 2013 +0530 typo corrected. commit 56258074283f4b6ab176cfde15a543db1abdd0a0 Author: abhinav Date: Thu Aug 8 16:16:15 2013 +0530 updated the documentation and learn.json files for links and comments commit 93d0842d527609d6430d4da3a25f78bf941f1cae Author: abhinav Date: Thu Aug 8 15:37:18 2013 +0530 moved durandal to the dependency-examples folder commit 764b5e2d784f9123b8109e1dc9d59d568d123eeb Author: abhinav Date: Thu Aug 8 12:45:30 2013 +0530 Added Durandal framework commit 71f080ce147789a3aae690ec0136008c80958b1d Author: Addy Osmani Date: Tue Aug 6 18:11:51 2013 +0100 Minor changes to readme, changelog in prep of release commit 7456c07cdcd6c17f883f56611e183f1ed31f5990 Author: Pascal Hartig Date: Tue Aug 6 19:06:53 2013 +0200 Added Angular+Firebase example to changelog commit 78ee32164b5b95528f92f65ba9a704d87045bef7 Author: Stephen Sawchuk Date: Tue Aug 6 12:28:54 2013 -0400 remove funnyfacejs from learn.json. commit 167aea5e06d3d9e1887be578745783be6112deb8 Author: Stephen Sawchuk Date: Tue Aug 6 11:23:17 2013 -0400 update to todomvc-common#0.1.8. commit 11dabd2e85d069caa248746ee01c625be47d6d83 Merge: 4244d8b fefb382 Author: Sindre Sorhus Date: Tue Aug 6 08:19:19 2013 -0700 Merge pull request #652 from passy/homepage-1.2 Updated homepage for 1.2 commit fefb382cc417597951309c45c4b8b39332724343 Author: Pascal Hartig Date: Tue Aug 6 17:01:26 2013 +0200 Updated homepage for 1.2 commit 4244d8b8977002941eec05b0ad8ca03f6910be4f Author: Addy Osmani Date: Tue Aug 6 14:41:54 2013 +0100 Adding Polymer to changelog commit 1f989ae3ce91567c557189c10dc9f15a1c5ab7aa Author: Sindre Sorhus Date: Tue Aug 6 15:05:03 2013 +0200 Remove funnyface from readme commit 910cf9ad17f5d04567b669107f8efd0baea4646a Author: Addy Osmani Date: Tue Aug 6 14:03:42 2013 +0100 Removing o_O implementation. Has not been updated in forever commit 6d5c1f0f29235ecfb689d3a1ebae061f99cc3443 Author: Greg Lobinski Date: Tue Aug 6 14:40:35 2013 +0200 Backbone naming tweaks Closes #610 Fixes #605 commit 3debb37ac2c54d716aaabc03a40ebdba0c267cd8 Merge: 9f55c02 3db7131 Author: Pascal Hartig Date: Tue Aug 6 05:39:26 2013 -0700 Merge pull request #641 from Foxandxss/angular-patch AngularJS - Add a check for changes to prevent unneeded saves. commit 9f55c0235b674ccd084e153c174e7fca9ecd1ec3 Author: Stephen Sawchuk Date: Tue Aug 6 14:36:00 2013 +0200 fix yui .focus() spec deviation RE #635 Closes #646 commit 3df87c7bc4034730793f1caaeef99c06272a3735 Author: MStumpp Date: Tue Aug 6 14:27:35 2013 +0200 Updated to meteor release 0.6.4 Closes #630 commit 7cb4d0e710223ffad283d6a187ea3c8efbd3d5e0 Author: Sindre Sorhus Date: Tue Aug 6 14:24:18 2013 +0200 index.html - head/body indentation commit 39a16fa4c8943c87354ef9095b7feacd598f86aa Author: Sindre Sorhus Date: Tue Aug 6 14:13:44 2013 +0200 Tweak formatting in codestyle.md commit a7278febebb6a3a490f6d0a4a00a9e9435d40bc0 Author: Sindre Sorhus Date: Tue Aug 6 14:10:32 2013 +0200 Remove gittip button commit bf3fef7d753c3def297644221663b0b522d52342 Author: Sindre Sorhus Date: Tue Aug 6 14:06:54 2013 +0200 Remove Chrome Frame thingy commit 3f696d48693d10ae6819564a4190fc701fd6578a Merge: fd3f4d0 be84165 Author: Sindre Sorhus Date: Tue Aug 6 04:58:58 2013 -0700 Merge pull request #599 from joyvuu-dave/backbone_marionette_require removes un-used (and un-needed) shim for backbone.localStorage commit fd3f4d0b43e5ccbb16a528dc222935f500a51a62 Merge: 2efa903 300b76c Author: Addy Osmani Date: Tue Aug 6 03:50:56 2013 -0700 Merge pull request #648 from tastejs/polymer-update Updating to latest official Polymer TodoMVC implementation commit 300b76cde944bed3a8f1b20e8a6433e9a369b025 Author: Pascal Hartig Date: Mon Aug 5 18:22:45 2013 +0200 polymer: code style update commit 2efa903770932915d8e4b9b8c59ea36ed69a14a2 Merge: f7db323 edde223 Author: Addy Osmani Date: Mon Aug 5 13:03:35 2013 -0700 Merge pull request #649 from passy/backbone-trimming Backbone: trim edits commit edde2237ba158f948e7ce8a5af7849d6086e3835 Author: Pascal Hartig Date: Mon Aug 5 19:56:02 2013 +0200 backbone: trim on edit (ref #635) commit aad9dd5de1d08297893285b5a37a86aa7efd814a Author: Pascal Hartig Date: Mon Aug 5 17:45:06 2013 +0200 polymer: bower_components GC commit 7a6824f552a556a9eb5273e279e8d33f62c35d95 Author: Addy Osmani Date: Mon Aug 5 15:43:26 2013 +0100 Updating to latest official Polymer TodoMVC implementation commit f7db32379c8363a67bf9075c693f9de505bdd6ee Author: Sindre Sorhus Date: Mon Aug 5 00:30:59 2013 +0200 Chrome Frame is no more commit 8c48866bbb8c031d554d60a23b3956e053671b0d Author: Pascal Hartig Date: Sun Aug 4 17:23:28 2013 +0200 firebase-angular: refactor controller commit 20100b515b5152e7f98dedb079d27d260f3fe0d1 Author: Pascal Hartig Date: Sun Aug 4 17:14:24 2013 +0200 firebase-angular: refactored todo filtering commit 246ebeee60b136973ba591636aa1a93e26cd5972 Merge: e82b3c2 8eeb1f4 Author: Addy Osmani Date: Sun Aug 4 07:59:31 2013 -0700 Merge pull request #638 from chenglou/upgrade Upgrade to React 0.4, fully compliant with specs commit e82b3c2071c7eab16589c22c2687198461002be5 Merge: 2ec5dc1 6defd80 Author: Addy Osmani Date: Sun Aug 4 07:50:36 2013 -0700 Merge pull request #633 from anantn/firebase Realtime: Addition for Firebase as a realtime framework commit 2ec5dc1145021d2bec34878eb35848e05d99f98d Author: Stephen Sawchuk Date: Fri Aug 2 15:13:37 2013 -0400 fix spine .focus() spec deviation. commit 92328d5045f786b850e8e8ae5bb5aa821d5e2ea3 Merge: ae3b53c 4fccfbf Author: Sindre Sorhus Date: Thu Aug 1 12:21:01 2013 -0700 Merge pull request #644 from BorisKozo/bugfixes Marionette - Changes for issue #642 commit ae3b53c9da9aa7a128b6e2e32ee4816f656b627e Author: Pascal Hartig Date: Thu Aug 1 19:30:22 2013 +0200 Add routing badge to Vanilla example commit 4fccfbf25b8141a9e15da3d5be31ddda3536f62b Author: Boris Kozorovitzky Date: Wed Jul 31 23:02:56 2013 +0300 Bumped versions Fixed issue #642 Couple of minor bug fixes commit 6f094c7e0e5211549900cf89411fe84f556e383c Merge: 401846d 5218856 Author: Addy Osmani Date: Wed Jul 31 00:32:58 2013 -0700 Merge pull request #639 from paulmillr/topics/update-brunch-chaplin Update Brunch with Chaplin. commit 52188567bf4c19e5c81cf353c9a5c27a75535516 Author: Paul Miller Date: Tue Jul 30 05:46:46 2013 +0300 Fix missing bower.json. commit 3db7131fed2896ba0903d6830a124379ae936bf9 Author: Jesus Rodriguez Date: Mon Jul 29 16:54:24 2013 +0200 Add an if to prevent unneeded saves commit 41470676865b94db5eb9ae2426c07d8dfc2323a7 Author: Paul Miller Date: Mon Jul 29 01:33:40 2013 +0300 Chaplin-brunch: do real model-level filtering, get rid of stuff. commit 466147a175f9cee30d315ef4c4d8ac8e24f6aaaf Author: Paul Miller Date: Sun Jul 28 04:04:55 2013 +0300 Don't use CSS for filtering in Chaplin-brunch. commit b4e7bc9408cfbdb453186c38ad3382e277cccc4e Author: Paul Miller Date: Sat Jul 27 22:50:31 2013 +0300 Update Brunch with Chaplin. 1. Add Bower integration. Since Brunch automatically concatenates all Bower stuff, we don’t need bower_components in repository (added to .gitignore, except of todomvc-common). 2. Update Brunch to 1.7. * Added automatic source maps generation, source maps are in repo too. 3. Update Chaplin to 0.10. * Remove `chaplin` module, switch to global variable. * Switch to new declarative events format. * Switch to controller compositions instead of static controllers. * Remove `application` since Chaplin now has this functionality by default. commit 8eeb1f471d8b44b090e6a5e2af76f82f98341e87 Author: Cheng Lou Date: Fri Jul 26 20:12:17 2013 -0400 directly set director as dep commit 401846de5b1c71d1aa0e4b2cda5cce237464fb29 Merge: b299ed3 f3a0719 Author: Sindre Sorhus Date: Fri Jul 26 05:43:33 2013 -0700 Merge pull request #637 from Roland1975/gh-pages refactor to reflect logic on line 62 commit f3a07193e57bbf6782ee5181c325b99fb086ec33 Author: Roland1975 Date: Fri Jul 26 13:33:34 2013 +0200 refactor to reflect logic on line 62 commit b299ed35d8d8e110880a89bc36741cee7f9d3c4c Author: Stephen Sawchuk Date: Thu Jul 25 20:50:47 2013 -0400 fix jquery .focus() spec deviation. commit 24c22e24fe654ecad60c9bfda8ce7cfa2d49a719 Merge: 26bdbb2 2d92e70 Author: Sindre Sorhus Date: Thu Jul 25 17:02:30 2013 -0700 Merge pull request #636 from glebm/patch-1 Remove ternary expressions commit 2d92e7066efd83ea0d9fb17b83db35f799f71146 Author: Gleb Mazovetskiy Date: Fri Jul 26 01:52:57 2013 +0200 Remove ternary expressions A more readable and scalable approach commit 1b16a19dfdc8b9ea8e4703f30779c5f2dd44a70a Author: Cheng Lou Date: Thu Jul 25 17:06:41 2013 -0400 Upgrade to React 0.4, fully compilant - Compilant with coding style. - Removed app.css. No need anymore since we freed id. - Render info footer separately (specs). - Tweak footer to make it pass jshint when compiled: - {''} after 'left'. - {''} around `clear completed`. - Breaking style for footer clearButton, `>` on the same line. - Rename cx and put it in Utils. - Routing with director. - Change some keyUp to keyDown (specs). - Strip form tags (specs? Referred to the stable ones). - Trim after editing item. - Manually autofocus (attribute not supported in ie9). - Input focus now triggers as a callback (because of batch rendering). - Controlled input. - Gutter at 80. - Class `completed` trim whitespace. - Remove bind. commit 6defd806a34d73407e380666062a1809fb6d5605 Author: Anant Narayanan Date: Mon Jul 22 12:30:28 2013 -0700 Add Firebase + AngularJS realtime example commit 26bdbb2d8875f345f41fd92e16c040bc6be6defd Merge: ba4b149 1617459 Author: Sindre Sorhus Date: Fri Jul 19 17:56:32 2013 -0700 Merge pull request #632 from gsydonkey/gh-pages Update index.html commit 1617459fcf59fb4ca43b9b485491a018ffd9c16c Author: gsydonkey Date: Sat Jul 20 06:18:42 2013 +0700 Update index.html Updated YUI seed file commit ba4b1496066f32d5f59d46e14fb9dd6a5c537920 Author: cam song Date: Sun Jul 14 12:20:00 2013 +0200 Close GH-629: Update YUI. commit 777a74ae1a568d569d33957d842d1de9a58f24e0 Merge: 5a2db4c c4fdbfc Author: Sindre Sorhus Date: Thu Jul 11 02:31:54 2013 -0700 Merge pull request #628 from Roland1975/gh-pages Refine selector by providing a context commit c4fdbfcb6d893a6fcf3d6389e22f7eff22f87930 Author: Roland Date: Wed Jul 10 11:41:01 2013 +0200 Use find() on selector commit 5a2db4c0f5d264e4221960daa7bc547ee83b564a Merge: e149f24 13d6a87 Author: Addy Osmani Date: Tue Jul 9 03:21:32 2013 -0700 Merge pull request #618 from snize/gh-pages Fixing #617 commit e149f24fe517ad6358ed2437cf7d8f1babfd955c Merge: 9a2ad38 4869d71 Author: Addy Osmani Date: Tue Jul 9 03:18:33 2013 -0700 Merge pull request #627 from passy/angular-esc angularjs: add escape behavior commit 9a2ad388f2d30dbd3dd3825b2d5433cbc3377dcc Merge: ba9a2fc 780f4c8 Author: Pascal Hartig Date: Tue Jul 9 02:47:57 2013 -0700 Merge pull request #625 from schubertha/gh-pages SAPUI5: bug fixes (tab preserves todo changes, enter always finishes editing) commit 780f4c82e0e78b1c3cc688b382f02fa6608b8e63 Author: Harald Schubert Date: Fri Jul 5 17:56:02 2013 +0200 SAPUI5: bug fixes (tab preserves todo changes, enter always finishes editing) commit 4869d71a2836444ca1daa973a42e5db13548b126 Author: Pascal Hartig Date: Mon Jul 8 20:41:05 2013 +0200 angularjs: add escape behavior commit ba9a2fc931aa39564161c014c2f5bc3af803ae4d Author: Stephen Sawchuk Date: Mon Jul 8 14:18:03 2013 -0400 (flight) fixes #626 - updated links. commit ecae4c32acd36f8c1288aa2513fa634a88860db9 Author: Pascal Hartig Date: Mon Jul 8 09:19:51 2013 +0200 flight: enable evil mode for templating engine commit 87c5b34532cd7ca370e886434c5be391638f4277 Merge: c77cbff 9692112 Author: Pascal Hartig Date: Fri Jul 5 07:41:17 2013 -0700 Merge pull request #624 from akudev/gh-pages SAPUI5: remove unneeded libraries from bootstrap commit 96921127e4f94caa8439cb4c8cd65420d36c2101 Author: Andreas Kunz Date: Fri Jul 5 15:44:22 2013 +0200 sapui5: remove unneeded libraries from bootstrap commit c77cbffaccc8976273ba93d648a557ce54823745 Author: Pascal Hartig Date: Wed Jul 3 23:55:00 2013 +0200 sapui5: added learnbar, fixed style loading If the script loader is triggered after loading the stylesheet, some of our overrides don't apply. commit c2f442d9171ebe24fe7c92c74a7043d15a40c582 Merge: e727203 39339df Author: Pascal Hartig Date: Wed Jul 3 23:37:03 2013 +0200 Merge branch 'schubertha-gh-pages' into gh-pages commit 39339dfd72b7a2afd3051daff0cb97e86eee9123 Author: Pascal Hartig Date: Wed Jul 3 23:36:41 2013 +0200 Added SAPUI to homepage, readme and changelog commit 7adf3303d273816fa704ecefbe228fda95d7a1f7 Author: Pascal Hartig Date: Wed Jul 3 23:29:32 2013 +0200 sapui: bower-ified app and moved script loading commit 9d27117f12c781a64828a203c460210be4099a94 Author: Pascal Hartig Date: Wed Jul 3 23:15:23 2013 +0200 sapui5: code style fixes commit e7fbe334bb09689fc2d14fef348263b3c25cd7b8 Author: Harald Schubert Date: Mon Apr 1 15:44:14 2013 +0200 TodoMVC using SAPUI5 commit 13d6a87651970ac567b08602b5a05f6696d88910 Author: Tomotsugu Kaneko Date: Mon Jul 1 18:26:43 2013 +0900 Remove 'autopublish, insecure' packages and add code for security reasons. commit e7272037fcce136074c1a3da2adb4b11bfd29c1b Author: Pascal Hartig Date: Mon Jul 1 10:51:31 2013 +0200 Added jQuery Annotated Source to Learn Bar Ref #620 commit 4c725caab03d1f24beb7435add76212f379d2a49 Merge: d82fcf5 50b52b2 Author: Sindre Sorhus Date: Mon Jul 1 01:49:04 2013 -0700 Merge pull request #620 from danekszy/gh-pages Add jQuery annotated source commit 50b52b2cc05e5e592c439fb62808bb886e590715 Author: Daniel Szymanek Date: Mon Jul 1 03:25:33 2013 +0200 Add jQuery annotated source I suggest adding annotated source to the readme, as it seems helpful to understand how most of the things work. commit d82fcf5a7450ab03a8d2d484c2943500fc4f2659 Merge: d50f6e6 cceaffa Author: Pascal Hartig Date: Sat Jun 29 15:06:00 2013 -0700 Merge pull request #616 from stephenplusplus/flight-bug (flight) bug with clearCompleted. commit cceaffa86f2c998d9847f7a063deb3b3b02e22ae Author: Stephen Sawchuk Date: Sat Jun 29 16:18:00 2013 -0400 (flight) fix clearCompleted bug. commit 757d0fcae68dbb0c5d0f21248125f5d39e2254af Author: Stephen Sawchuk Date: Sat Jun 29 16:15:08 2013 -0400 (flight) code style changes. commit f588bcdee2cee8c3d2151666ec0c2aa98af7ff92 Author: Tomotsugu Kaneko Date: Fri Jun 28 18:16:26 2013 +0900 Fixed indentations. commit 006fbfaa0aea19a67f9002041f6bb7d5857cde1b Author: Tomotsugu Kaneko Date: Fri Jun 28 17:44:28 2013 +0900 fixes #617 - added Meteor.methods To call the `remove` method on the server side from the client side. commit eb2d7cbbc96c47d44d982cb7fe85065710bf4004 Author: Tomotsugu Kaneko Date: Fri Jun 28 17:36:13 2013 +0900 added insecure package commit d50f6e65dcbee66787113b502fbc287b700b25aa Merge: c488f56 b9ffe3e Author: Addy Osmani Date: Tue Jun 25 10:17:28 2013 -0700 Merge pull request #608 from tastejs/polymer Move Polymer about of labs commit b9ffe3e0c7bebe788e546f4cc95cc10442fc408a Author: Addy Osmani Date: Tue Jun 18 10:21:51 2013 +0100 Moving Polymer out of labs commit c488f5644bffda4a8a2012240ea35d80d5a88f97 Merge: 575d1e6 57e70d6 Author: Stephen Sawchuk Date: Tue Jun 18 16:46:37 2013 -0700 Merge pull request #609 from cujojs/cujojs-update Update to latest cujoJS releases commit 57e70d6d988e9cf09ec28a0f667ef74ef7d814f2 Author: Brian Cavalier Date: Tue Jun 18 11:11:37 2013 -0400 Update to latest cujoJS releases: wire 0.10.0, curl 0.7.4, when 2.1.1 commit 575d1e612627c1001e50b366c47f69331b9a9fb6 Author: Stephen Sawchuk Date: Tue Jun 18 12:02:59 2013 -0400 Fix Polymer homepage link in learn.json. commit 7b86797ffecec118c6c6cd90ceed558f50861954 Author: Stephen Sawchuk Date: Tue Jun 18 11:44:29 2013 -0400 add Learn bar to labs -> Polymer. commit db9cb67d6374f56e4071fa7f90598871a7794b6f Merge: 5dd89f8 39781cc Author: Pascal Hartig Date: Tue Jun 18 02:18:02 2013 -0700 Merge pull request #607 from acanby/fix_angularjs_readme Updated AngularJS links in the readme.md commit 5dd89f809877c2b96bd778c8370d3c0b5fcd5bfb Author: Addy Osmani Date: Tue Jun 18 10:13:06 2013 +0100 Updating learn.json with initial entry for Polymer commit 39781cc5c5d4836c4dad565705e75ce8767be459 Author: Andrew Canby Date: Tue Jun 18 19:06:01 2013 +1000 Updated AngularJS links in the readme.md commit 895907666b3cc722afd5139c39396252f1ee9c88 Author: Addy Osmani Date: Tue Jun 18 09:58:02 2013 +0100 Fixes #576 - adds new Polymer TodoMVC implementation. Add entry to the homepage commit e82d6e4f9bd980459363d9c4d349941065467ae1 Author: Pascal Hartig Date: Tue Jun 18 01:05:24 2013 +0200 Updated link to Montage Quick Start Fix #606 commit 27ce25f86c5afef1e15fc255f2d6e625219bd0a0 Author: Pascal Hartig Date: Mon Jun 17 22:23:51 2013 +0200 Added React to changelog commit 9bb06463a934c1a0ad819103a025ce6f1fef6277 Merge: f22dbf8 37589b3 Author: Pascal Hartig Date: Mon Jun 17 22:23:01 2013 +0200 Merge branch 'petehunt-react' into gh-pages commit 37589b39c3394147b61e865fa2ea0216d36680bd Author: petehunt Date: Wed May 29 23:11:09 2013 -0700 Initial add of React TodoMVC to labs React is a JavaScript library for building user interfaces by Facebook and Instagram. It powers many components on Facebook.com and all of Instagram.com is written with it. We have two TodoMVC examples checked into our repo: this one, which has no dependencies, and another one which showcases Backbone integration. I've only included the first one for now, if you guys think it's a good idea I can put out a PR for the one with Backbone integration. I read the contributing guide and I think this meets the standards, let me know if I missed something. commit f22dbf85dddb3892369283cb1dc63b64153a05fe Author: Stephen Sawchuk Date: Thu Jun 13 20:50:34 2013 -0400 fixes #601 - o_O jquery downgrade. commit f83a3caa1db60b2f687db211ba1cedccde4095d7 Author: Stephen Sawchuk Date: Thu Jun 13 16:53:07 2013 -0400 DUEL bug fixed, code style. commit b852875ed5dcca5e798117441a8debc67be988d0 Merge: 45a312d 966886b Author: Pascal Hartig Date: Wed Jun 12 15:14:05 2013 -0700 Merge pull request #600 from theoptips/gh-pages fixed base.css input::-moz-placeholder commit 966886b679c71a829854a6c6121fe04d4b7d473d Author: Dilys Sun Date: Wed Jun 12 14:59:00 2013 -0700 fixed input::-moz-placeholder commit be8416523cd792d4fe8dce89b4ebc092c18c17b3 Author: Dave Riddle Date: Tue Jun 11 15:55:34 2013 -0600 removes un-used (and un-needed) shim for backbone.localStorage commit 45a312d8e0b7c66dd6263c81bf5513d4c0c802a1 Author: Sindre Sorhus Date: Sat Jun 8 21:03:40 2013 +0200 Fix link to SocketStream readme commit d5a4a929d33cd9435db333bfd4b45d25081ef5e0 Author: Stephen Sawchuk Date: Sat Jun 8 10:15:11 2013 -0300 Correct angularjs homepage URL commit 3157437d6221128bc1d6ab7926089f737963ae3c Merge: d76a1f1 e811222 Author: Addy Osmani Date: Sat Jun 8 02:24:55 2013 -0700 Merge pull request #595 from acanby/fix_angularjs_readme Fixed readme.md AngularJS links to .org instead of .com commit e81122280f44b178acac9066b175fefaf392d073 Author: Andrew Canby Date: Sat Jun 8 15:28:28 2013 +1000 Fixed AngularJS links to .org instead of .com commit d76a1f144112d49f571762cd725bdb6638eb5342 Author: Stephen Sawchuk Date: Tue Jun 4 20:06:22 2013 -0400 somajs code style + components -> bower_components. commit 3a6747c36cc21925fc2f631fa4570e3ad1390fd0 Author: Stephen Sawchuk Date: Tue Jun 4 10:55:08 2013 -0400 epitome casing issue. commit 3b8c596a2b3b9614917f0d1db7db90d98bd89fa3 Merge: cc132b8 29f9c0a Author: Stephen Sawchuk Date: Tue Jun 4 05:39:51 2013 -0700 Merge pull request #591 from stephenplusplus/epitome-bug Epitome Code Style + Spec Issue commit 29f9c0a79e7b472c5e5f0a7e25545d0d6516419a Author: Stephen Sawchuk Date: Mon Jun 3 23:01:13 2013 -0400 epitome hides footer when there are no todos. commit cc132b80722ed2c941126498d6ee01d51cdef9ea Merge: f15ab3f 513ef4d Author: Stephen Sawchuk Date: Mon Jun 3 19:30:18 2013 -0700 Merge pull request #590 from callmehiphop/gh-pages Tweaked Montage lab to show the Learn sidebar. commit 513ef4d99a469b913b185b16a6ea27cb1d8b4aba Author: callmehiphop Date: Mon Jun 3 21:40:30 2013 -0400 Tweaks to allow the Learn side bar to not be destroyed commit f15ab3f9a85c489febce689cbf209ff44be132cd Merge: 3aab99f 00dcae1 Author: Stephen Sawchuk Date: Mon Jun 3 17:43:44 2013 -0700 Merge pull request #589 from callmehiphop/gh-pages Updated Enyo/Backbone lab to not remove the Learn sidebar. commit 00dcae174b2310c529707acc6c6e418ce9b807b9 Author: callmehiphop Date: Mon Jun 3 20:30:21 2013 -0400 Updated enyo/backbone example to not kill the sidebar commit 3aab99f3c82ac78dedadf68ede0d84b86725a26b Author: Stephen Sawchuk Date: Mon Jun 3 12:43:48 2013 -0400 rappidjs select all bug + code style. commit 45e8b94b088db27d442bb7283040e88e72ae88a8 Merge: 48b8ca7 ee9db31 Author: Stephen Sawchuk Date: Mon Jun 3 09:14:11 2013 -0700 Merge pull request #573 from stephenplusplus/bbm backbone_marionette_require code style + spec comp. commit ee9db311ed74356b1d3572651bef6f1055b1a171 Author: Stephen Sawchuk Date: Sun May 26 20:18:53 2013 -0400 backbone_marionette_require code style. commit 48b8ca7dcd77299521c868c193c9de5f7de4c277 Author: Stephen Sawchuk Date: Sat Jun 1 19:59:51 2013 -0400 fixes #585 - update todomvc-common. commit 2b680e1f2231eae93ead90a0fa36582942259900 Author: Stephen Sawchuk Date: Sat Jun 1 15:00:24 2013 -0400 maria uses bower for all dependencies. commit c18448eefaf6b34829adc29dc131dc6157d591c7 Author: Stephen Sawchuk Date: Fri May 31 13:43:11 2013 -0400 closes #584 - backbone_marionette footer issues. commit ff32a65f4b1b2a8513e29a1d0f9659daa4a8f69b Author: Stephen Sawchuk Date: Fri May 31 12:27:47 2013 -0400 add somajs_require example to learn.json. commit 6422876906d94996a98bfce641639800d619e593 Merge: 0f75cb5 ba3ecf5 Author: Stephen Sawchuk Date: Fri May 31 09:25:39 2013 -0700 Merge pull request #586 from somajs/somajs-module soma.js baseline update and added to module loader section commit ba3ecf54c73d2d0c07407a0d2eee6e52febdc800 Author: Romuald Quantin Date: Fri May 31 17:17:25 2013 +0100 soma.js baseline update and added to module loader section commit 0f75cb53632b9f1328488027606fa4eeb590dab2 Author: Addy Osmani Date: Fri May 31 16:39:11 2013 +0100 Fixes #305 - bringing lower case consistency to app.Todos commit 834b79f6cd5053a9360e4e3d177e068491fcbd12 Merge: 3af9f7b 10dee13 Author: Addy Osmani Date: Fri May 31 08:27:30 2013 -0700 Merge pull request #553 from somajs/somajs soma.js v2 updates commit 10dee1331fd2915a173341aa908f37a84674f031 Author: Romuald Quantin Date: Wed May 8 17:08:49 2013 +0100 soma.js version 2 in progress todo scope in models updated somajs update and comments somajs update soma.js and require.js added whitespace update main view hide update jshint errors update jshint errors update cleanup requirejs dependencies save on blur and remote persistent editing todomvc-common update on soma.js cleanup bower components in soma.js commit 3af9f7bbf915036a5fa903166ffda0dc30acdad3 Author: Pascal Hartig Date: Thu May 30 23:52:52 2013 +0200 o_O: Added missing footer note commit 1dd3f1f56af2586928c9268e5362aed5d0407b08 Merge: cc045d6 3911ab5 Author: Addy Osmani Date: Thu May 30 02:20:10 2013 -0700 Merge pull request #583 from epitome-mvc/epitome-0.3.1 fix for #577 commit 3911ab5df18c6dbfd7808307b3b334cf9a426b6a Author: Dimitar Christoff Date: Thu May 30 10:08:19 2013 +0100 fix for #577 commit cc045d6e1af4d3c4369beb3ace07fa52760594ba Author: Pascal Hartig Date: Thu May 30 02:09:27 2013 +0200 Updated changelog commit 85a30be73aba56beb9b606911b27e7242f3e9fee Merge: 3630eda b975647 Author: Pascal Hartig Date: Wed May 29 17:06:58 2013 -0700 Merge pull request #575 from troopjs/troopjs Updated project to TroopJS 2.x commit 3630eda0431094d46057144e3a51692177cc28ae Merge: 27850ea fcc5981 Author: Stephen Sawchuk Date: Wed May 29 13:47:13 2013 -0700 Merge pull request #579 from stephenplusplus/knockoutjs_require knockoutjs_require codestyle. commit fcc5981c69d0c904cc5bb56e03311db0f91c4d37 Author: Stephen Sawchuk Date: Wed May 29 16:45:00 2013 -0400 knockoutjs_require codestyle. commit 27850eac46d6c89b0308ddfd9dbbb948b45619f5 Merge: d59b261 ac44ecc Author: Stephen Sawchuk Date: Wed May 29 13:30:10 2013 -0700 Merge pull request #578 from stephenplusplus/canjs_require restructured canjs_require + code style. commit ac44ecc6163b89b7cfc64118a56317ed1b944a9a Author: Stephen Sawchuk Date: Wed May 29 16:26:36 2013 -0400 restructured canjs_require + code style. commit b975647316b5a13d401a604c643804061987c927 Author: Mikael Karon Date: Mon May 27 11:46:58 2013 +0800 Updated project to TroopJS 2.x * Fix jshint errors. * Clean bower_components. * Update global, remove local learn.json. * Only edit when dblclick on `.view label`. * Update title from Template -> TroopJS. * Use .toggle (to simplify reading the code). * Add support for ESC_KEY during edit. * Escape title in template. * Use unminified versions of components. * Remove comments from html. * Remove `type` from script attribute. * Remove `baseUrl` from requirejs config. * Convert double to single quotes for javascript (in index.html). * Move troopjs -> troopjs_require and update the main index.html file to reflect updates in the framework. * Use `.focus()` instead of `.select()`. * Use Array natives for iteration. * Remove redundant package configuration. * `else` and `else if` on the same row as bracket. * No space before `:`. * Break `define` into multiple rows. * Simplify filter. * Stay consistent with anonymous function usage. * Add newlines. * Apply the same fix as in tastejs/todomvc@dca5107. * Don't quote keys. * Remove self evident comments. * Update storage code to _always_ restore UI on fail. commit d59b2617d1c17ef32de824bf33c05849a2e91fcf Author: Sindre Sorhus Date: Mon May 27 20:07:58 2013 +0200 site: also fix the alt attr on Stephen and formatting and remove `and` commit 534a2c256bb61bc5ba239384370853bf17242f9f Author: Sindre Sorhus Date: Mon May 27 20:06:08 2013 +0200 site: couldn't sleep because of the different url formats commit 4163de6f7141675b553ad01b6c861a9882f1bf8f Author: Stephen Sawchuk Date: Mon May 27 00:34:44 2013 -0400 (infobar) append link_groups if they exist. commit 609f6cc11acb522bec6a3f7c0a6c4559f5583062 Author: Stephen Sawchuk Date: Sat May 25 16:58:42 2013 -0400 updated todomvc-common to 0.1.7. commit e5dbc9bfb8a7ac998ba8c746272e346efb9a2560 Author: Stephen Sawchuk Date: Sat May 25 09:25:06 2013 -0400 updated todomvc-common; now using _ templates. commit c7d402036ff27f7489ea029d0cf42628ce7fdea5 Author: Addy Osmani Date: Sat May 25 13:17:02 2013 +0200 Adding all team members to the homepage commit 318b974fdf17dd3a4233c8bff3c535bbe39c7ae9 Author: Addy Osmani Date: Sat May 25 13:10:51 2013 +0200 Adding Stephen Sawchuk to the core team commit 0fc68319eb6938a9a4e7c94d9da92f0fb32ae0b9 Author: Pascal Hartig Date: Fri May 24 18:18:58 2013 +0200 AngularJS-Perf: Applied trim patch commit dabdef2b1cb7096c56cc9297253cb63527d33089 Author: Pascal Hartig Date: Fri May 24 18:14:06 2013 +0200 AngularJS+Require: Applied trim patch commit a9abf95d85a0f3ace06abacfe8530afd3a4fcec2 Merge: ae73f1c c462121 Author: Sindre Sorhus Date: Thu May 23 07:04:26 2013 -0700 Merge pull request #571 from passy/angular-trim AngularJS: Trim todos on save commit c462121c4e96e93af55120f85d5482b2105dc13b Author: Pascal Hartig Date: Thu May 23 13:19:27 2013 +0200 AngularJS: Trim todos on save commit ae73f1c9aad2ec33f88cdb5af612a1307af3324f Author: Pascal Hartig Date: Thu May 23 13:05:13 2013 +0200 AngularJS: dependency example + angular-perf updated commit 1669496bf5a18862b91efdb60f34880e4610fb6c Author: Pascal Hartig Date: Thu May 23 13:01:30 2013 +0200 AngularJS: architecture example updated to 1.0.7 commit b7d77e8ac18c4ced9219906d39d215d12340fe38 Author: Pascal Hartig Date: Thu May 23 12:58:52 2013 +0200 CanJS: Updated to 1.1.5 commit 66100a724e833ffb814d63f1c01441dc58cf98d1 Merge: a71f2a3 63dfcd4 Author: Pascal Hartig Date: Wed May 22 09:21:52 2013 -0700 Merge pull request #569 from stephenplusplus/gh-pages #568 Fix - insertAdjacentElement commit 63dfcd428bf36be1c9ae08c65de42c39dc6ec943 Author: Stephen Sawchuk Date: Wed May 22 12:10:39 2013 -0400 #568 - insertAdjacentElement vs insertAdjacentHTML. commit a71f2a35dfd9dcb9c8297391bcc09c0f6ef70655 Merge: d54c743 3a4198d Author: Pascal Hartig Date: Tue May 21 11:18:37 2013 +0200 Merge branch 'stephenplusplus-patch-1' into gh-pages commit 3a4198d6bc1d2a61ad016c7c362e99058b7ad970 Author: Stephen Sawchuk Date: Tue May 21 02:06:43 2013 -0300 cujo.js -> cujoJS Seems they prefer the cujoJS phrasing over cujo.js. commit d54c743d80ad54cf5dc13ccca29c17e381d28b92 Merge: b78a80a 05b1ce1 Author: Pascal Hartig Date: Mon May 20 14:20:25 2013 -0700 Merge pull request #565 from stephenplusplus/gh-pages Updated the cujoJS readme. commit 05b1ce1bc1291f2122f0f0135bd158ca6f1843c5 Author: Stephen Sawchuk Date: Mon May 20 16:59:34 2013 -0400 cujo readme updated. commit b78a80a914735ed9dffff022074f9a14c2d4b6bf Author: Pascal Hartig Date: Mon May 20 21:21:54 2013 +0200 Added know cujoJS to learn.json commit af7fafc86ae2448c823fc91d5ac3dfb2d7c4a511 Author: Pascal Hartig Date: Mon May 20 21:19:27 2013 +0200 cujo css: consistent css indention commit 349aa2cd00571128f84f210993366ffe851eaffd Author: Pascal Hartig Date: Mon May 20 21:18:12 2013 +0200 Updated changelog commit 4f633c598f4cbb8f229a97a82fbb86b36c9605fb Author: Pascal Hartig Date: Mon May 20 21:16:25 2013 +0200 Removed es5 option from jshintrc It's a default as of jshint 2.0 commit 8152c9f8b808c12323aa739d7d8856c5d4b824da Merge: 9972d21 b8d9ae5 Author: Pascal Hartig Date: Mon May 20 12:15:09 2013 -0700 Merge pull request #556 from cujojs/cujo-lib-update Update to latest cujo releases commit b8d9ae5cfd6a7d024d263fee639c0f825502e99c Author: Brian Cavalier Date: Fri May 10 14:53:00 2013 -0400 Update to latest cujo releases via bower. Handle enter key when editing todo but not changing it. Remove Template by. Remove unnecessary files. commit 9972d21e67a16f89cd44b55beb3137d14f9ad093 Author: Pascal Hartig Date: Sat May 18 14:53:53 2013 +0200 Unbreak todomvc.com hosting commit c5ffea436a06a19be9982dfe3ea57fc6f19794a4 Merge: 868271f 3e6e853 Author: Addy Osmani Date: Sat May 18 04:38:14 2013 -0700 Merge pull request #547 from stephenplusplus/readmes More helpful readmes for beginners - epic work by stephen. commit 3e6e853bd02decc37340919907044860bdb3e6c6 Author: Stephen Sawchuk Date: Thu May 16 11:52:56 2013 -0400 add more helpful readmes and learn.json. commit 868271f6cccebb9ce2c1f5b7b2441aa2ad34d67f Merge: d3e1ac8 5f742d2 Author: Addy Osmani Date: Fri May 17 10:52:37 2013 -0700 Merge pull request #558 from thebakeryio/refactoring/update-count Refactoring/update count commit 5f742d2790792a035678c70786f70c525cd3334c Author: callmephilip Date: Mon May 13 09:27:09 2013 -0700 move logic from updateCount into the view rendering routine update footer template to support declarative task stats rendering adjust if block formatting remove unnecessary escaping from the footer template adjust variable declaration statements adjust indentation in the footer template commit d3e1ac8b93d7fe214372d0e2043d2f1b2b469aec Merge: 7a337a5 57d0c3e Author: Pascal Hartig Date: Fri May 17 01:37:00 2013 -0700 Merge pull request #563 from txmikester/angular-test-fix Fixed broken AngularJS test runner commit 57d0c3ea9c9e62d74f7673318e524920ca2efb0f Author: Mike Haney Date: Fri May 17 01:42:23 2013 -0500 Fixed broken AngularJS test runner Incorrect paths in the testacular.conf.js file prevented the tests from running. Also, updated package.json to use karma instead of testacular (project was renamed) commit 7a337a583aa0cfb51bd85b0b73d22a657a7cfd7d Merge: b6d929c f434c38 Author: Pascal Hartig Date: Thu May 16 01:19:20 2013 -0700 Merge pull request #562 from rahulcs/ember-revision Update ember data revision from 11 to 12 commit f434c38b7dd61bb8f148c5329a8e4d5c95bda82a Author: Rahul Chanila Date: Thu May 16 13:33:26 2013 +0530 Update ember data revision from 11 to 12 commit b6d929c019f0d5022c8c34b63fdb2a9be079cf00 Author: Addy Osmani Date: Sat May 11 19:18:36 2013 +0100 For #453 - adds initial angular-perf readme. commit e3674e71b15dc46f35482551320e22ada88425d7 Author: Addy Osmani Date: Sat May 11 18:58:57 2013 +0100 Several minor updates: - Add avatar and description for Gianni - Add Pascal to the copyright list - Fleshing out RequireJS apps in readme commit 4ad2192b8ee6fb5dee52dd6bd3db83bb97c629fd Author: Sindre Sorhus Date: Sat May 11 18:47:11 2013 +0200 Update paths to tastejs/todomvc repo commit e38f48289302ece4b97e47090d72b5c0be96c23f Merge: ba32f91 50c49f7 Author: Sindre Sorhus Date: Thu May 9 11:26:42 2013 -0700 Merge pull request #555 from stephenplusplus/template-bower template/ updated with bower.json/bower_components. commit 50c49f7373f1254f7aaa64a5052c7422d8dfddba Author: Stephen Sawchuk Date: Thu May 9 13:28:54 2013 -0400 template/ updated with bower.json/bower_components. commit ba32f91873c968b98f8192ac75b88b1a6eaa4c3e Merge: c08c83b c9d80c1 Author: Sindre Sorhus Date: Thu May 9 06:39:47 2013 -0700 Merge pull request #552 from stephenplusplus/cujo_bower cujo updated to use bower. commit c9d80c13d4a897a5d13ccaeec64176c65df98d0e Author: Stephen Sawchuk Date: Thu May 9 04:56:20 2013 -0400 cujo updated to use bower. commit c08c83b8b07a17b5daa9eb01b9aca32cc343812a Merge: ac970f5 a59d566 Author: Pascal Hartig Date: Sun May 5 17:44:22 2013 -0700 Merge pull request #551 from stephenplusplus/ember_sample add source and demo link to ember+rjs readme commit a59d566a7148fb5348af87e69d25f658bc66c0ed Author: Stephen Sawchuk Date: Sun May 5 20:41:36 2013 -0400 add source and demo link to ember+rjs readme commit ac970f5e8c3cf4734dd84bf14923ea1abd88aac6 Author: Pascal Hartig Date: Mon May 6 01:23:05 2013 +0200 emberjs_require: Fix redirect case sensitivity commit cde6f81a0b2d8fd404ad18dc166964dcf4b171db Author: Pascal Hartig Date: Mon May 6 01:17:17 2013 +0200 Updated changelog, homepage, readme to reflect ember+rjs removal commit e8cfeae541cd3780baa488d3af009fd40c56836f Author: Pascal Hartig Date: Mon May 6 01:14:38 2013 +0200 Remove emberjs-require example, redirect to README Close #528 commit 41ef0d4a60ac8c92414c11fba390d96fae6c293e Merge: 37174a6 dccfdac Author: Sindre Sorhus Date: Sun May 5 07:26:19 2013 -0700 Merge pull request #545 from thebakeryio/feature/backbone-marionette-model-shortcuts use Marionette's event hashes for Model and Collection events commit 37174a69a616a200c27d854aaab13a254180cb1c Merge: 29a5abc 629c07e Author: Addy Osmani Date: Sat May 4 04:02:14 2013 -0700 Merge pull request #550 from OscarGodson/patch-1 Updated README to reflect new Vanilla JS project commit 629c07ebd17a956893d2b2a305f1e2632b60f085 Author: Oscar Godson Date: Fri May 3 15:02:33 2013 -0700 Updated README to reflect new Vanilla JS project commit 29a5abcd202ba08527749a8ddb31eeb3d4de985b Merge: b8365f4 3e59664 Author: Addy Osmani Date: Fri May 3 14:16:46 2013 -0700 Merge pull request #510 from OscarGodson/gh-pages VanillaJS app rewrite - landed! commit b8365f4b047e8a6732a3a3ec60f03fc78fef7bb4 Merge: 8ea9aef 537d6e1 Author: Pascal Hartig Date: Thu May 2 12:13:03 2013 -0700 Merge pull request #548 from stephenplusplus/serenadejs-bug serenade.js typo. commit 537d6e1f904110a4dd6c5c4c2c7ed08f1f618fe2 Author: Stephen Sawchuk Date: Thu May 2 15:11:15 2013 -0400 serenade.js typo. commit dccfdac94635f306bb5c788b77605d11ee1fa43a Author: callmephilip Date: Wed May 1 10:44:08 2013 -0700 use Marionette's event hashes for Model and Collection events refer to Marionette's documentation for more details https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.view.md#viewmodelevents-and-viewcollectionevents commit 3e59664cafb2260e468c3ffaa6c60df139b01068 Author: Stephen Sawchuk Date: Wed May 1 13:17:31 2013 -0400 component.json/components -> bower.json/bower_components commit 6de9e4b74e8d2d33b9bfca2a03a67d4e2d1c1e62 Author: Oscar Godson Date: Wed May 1 08:41:38 2013 -0700 Ticket #510 - Put all the codez in a global namespace commit f7e1b55e3ef0378b185312a3a95b7b84ac387fe5 Author: Stephen Sawchuk Date: Wed May 1 11:08:06 2013 -0400 Array.filter && !empty todos && `addItem` simplification. commit e6f149763f6fc551b5871a1de0ea73dad99c1296 Author: Oscar Godson Date: Sat Nov 24 22:04:54 2012 -0800 TodoMVC app in vanilla JS. No, that's not a framework. --- .gitignore | 1 + .jshintrc | 1 - CNAME | 2 +- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- architecture-examples/agilityjs/index.html | 4 +- architecture-examples/agilityjs/readme.md | 33 + .../angularjs-perf/bower.json | 2 +- .../bower_components/angular/angular.js | 602 +- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- .../angularjs-perf/index.html | 6 +- .../angularjs-perf/js/controllers/todoCtrl.js | 16 +- .../angularjs-perf/readme.md | 42 + architecture-examples/angularjs/bower.json | 4 +- .../bower_components/angular/angular.js | 602 +- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- architecture-examples/angularjs/index.html | 9 +- .../angularjs/js/controllers/todoCtrl.js | 24 +- .../angularjs/js/directives/todoEscape.js | 18 + architecture-examples/angularjs/readme.md | 36 + .../angularjs/test/config/testacular.conf.js | 4 +- .../angularjs/test/package.json | 21 +- .../angularjs/test/unit/todoCtrlSpec.js | 76 +- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- architecture-examples/backbone/index.html | 8 +- .../backbone/js/collections/todos.js | 4 +- .../backbone/js/routers/router.js | 6 +- .../backbone/js/views/{app.js => app-view.js} | 30 +- .../js/views/{todos.js => todo-view.js} | 7 +- architecture-examples/backbone/readme.md | 29 + architecture-examples/canjs/bower.json | 4 +- .../bower_components/canjs/can.jquery.js | 7401 +++--- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- architecture-examples/canjs/index.html | 6 +- architecture-examples/canjs/readme.md | 60 +- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- architecture-examples/closure/index.html | 88 +- architecture-examples/closure/readme.md | 49 +- architecture-examples/dart/.bowerrc | 3 + architecture-examples/dart/bower.json | 7 + architecture-examples/dart/readme.md | 46 +- architecture-examples/dart/web/assets/base.js | 40 - architecture-examples/dart/web/assets/ie.js | 27 - .../bower_components}/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 + .../todomvc-common}/bg.png | Bin architecture-examples/dart/web/index.html | 85 +- architecture-examples/dojo/bower.json | 7 + .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common}/bg.png | Bin architecture-examples/dojo/index-1.7.html | 16 +- architecture-examples/dojo/index.html | 78 +- architecture-examples/dojo/readme.md | 55 +- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- architecture-examples/emberjs/index.html | 4 +- .../emberjs/js/libs/ember-data.js | 683 +- .../emberjs/js/models/store.js | 2 +- architecture-examples/emberjs/readme.md | 31 + architecture-examples/gwt/bower.json | 7 + .../bower_components/todomvc-common}/base.css | 181 +- .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common}/bg.png | Bin architecture-examples/gwt/css/app.css | 8 +- architecture-examples/gwt/index.html | 14 +- architecture-examples/gwt/readme.md | 58 +- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- architecture-examples/jquery/index.html | 4 +- architecture-examples/jquery/js/app.js | 18 +- architecture-examples/jquery/readme.md | 33 + architecture-examples/knockback/bower.json | 9 + .../backbone.localStorage.js | 217 + .../bower_components/jquery/jquery.js | 8755 +++++++ .../bower_components/todomvc-common}/base.css | 183 +- .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin architecture-examples/knockback/index.html | 127 +- architecture-examples/knockback/readme.md | 39 +- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- architecture-examples/knockoutjs/index.html | 2 +- architecture-examples/knockoutjs/readme.md | 37 +- architecture-examples/maria/bower.json | 4 +- .../aristocrat-bower}/aristocrat.js | 4 +- .../maria-bower}/maria.js | 338 +- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- architecture-examples/maria/index.html | 60 +- .../maria/js/models/TodosModel.js | 28 +- .../maria/js/views/TodosView.js | 2 +- architecture-examples/maria/readme.md | 18 + architecture-examples/polymer/AUTHORS | 9 + architecture-examples/polymer/CONTRIBUTING.md | 63 + architecture-examples/polymer/LICENSE | 27 + architecture-examples/polymer/PATENTS | 23 + architecture-examples/polymer/README.md | 44 + architecture-examples/polymer/app/app.css | 206 + .../polymer}/bower.json | 6 +- .../director/build/director.js | 712 + .../director/build/director.min.js | 7 + .../bower_components/director/build/ender.js | 3 + .../bower_components/polymer/polymer.min.js | 35 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components}/todomvc-common/bg.png | Bin .../polymer/elements/td-input.html | 22 + .../polymer/elements/td-item.css | 160 + .../polymer/elements/td-item.html | 56 + .../polymer/elements/td-model.html | 74 + .../polymer/elements/td-todos.css | 164 +- .../polymer/elements/td-todos.html | 81 + architecture-examples/polymer/index.html | 29 + .../lib-elements/flatiron-director.html | 31 + .../lib-elements/polymer-localstorage.html | 53 + .../lib-elements/polymer-selection.html | 64 + .../lib-elements/polymer-selector.html | 198 + .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- architecture-examples/spine/index.html | 120 +- architecture-examples/spine/js/app.js | 11 +- .../spine/js/controllers/todos.js | 8 +- architecture-examples/spine/js/models/todo.js | 3 +- architecture-examples/spine/readme.md | 48 +- .../spine/src/controllers/todos.coffee | 2 +- architecture-examples/yui/bower.json | 7 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes architecture-examples/yui/index.html | 162 +- architecture-examples/yui/js/app.js | 5 +- .../yui/js/views/todoview.js | 9 +- architecture-examples/yui/readme.md | 26 + assets/base.css | 2 +- assets/base.js | 14 +- changelog.md | 9 +- codestyle.md | 31 +- contributing.md | 8 +- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- .../backbone_require/index.html | 54 +- .../backbone_require/readme.md | 29 + .../emberjs_require/css/app.css | 131 - .../emberjs_require/index.html | 29 +- dependency-examples/emberjs_require/js/app.js | 43 - .../js/app/controllers/entries.js | 72 - .../js/app/controllers/todos.js | 27 - .../emberjs_require/js/app/models/store.js | 80 - .../emberjs_require/js/app/models/todo.js | 20 - .../emberjs_require/js/app/router.js | 93 - .../js/app/specs/controllers/todos.js | 65 - .../emberjs_require/js/app/specs/helper.js | 16 - .../js/app/specs/models/store.js | 31 - .../emberjs_require/js/app/specs/todoMVC.js | 112 - .../js/app/specs/views/basic_acceptance.js | 29 - .../js/app/templates/clear_button.html | 5 - .../js/app/templates/filters.html | 11 - .../js/app/templates/items.html | 7 - .../js/app/templates/stats.html | 7 - .../js/app/views/application.js | 69 - .../js/app/views/clear_button.js | 22 - .../emberjs_require/js/app/views/filters.js | 26 - .../emberjs_require/js/app/views/items.js | 50 - .../emberjs_require/js/app/views/stats.js | 22 - .../js/lib/ember-latest.min.js | 18 - .../emberjs_require/js/lib/require/require.js | 31 - .../emberjs_require/js/lib/require/text.js | 11 - dependency-examples/emberjs_require/readme.md | 18 +- dependency-examples/flight/app/js/app.js | 56 +- .../flight/app/js/data/stats.js | 62 +- .../flight/app/js/data/todos.js | 162 +- dependency-examples/flight/app/js/store.js | 16 +- .../flight/app/js/ui/main_selector.js | 34 +- .../flight/app/js/ui/new_item.js | 46 +- dependency-examples/flight/app/js/ui/stats.js | 70 +- .../flight/app/js/ui/todo_list.js | 213 +- .../flight/app/js/ui/toggle_all.js | 42 +- .../flight/app/js/ui/with_filters.js | 42 +- dependency-examples/flight/app/js/utils.js | 6 +- .../flight/app/templates/stats.html | 6 +- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- dependency-examples/flight/index.html | 4 +- dependency-examples/flight/readme.md | 19 + index.html | 625 +- .../ariatemplates/bower.json | 7 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../ariatemplates/index.html | 72 +- .../ariatemplates/readme.md | 27 + .../backbone.xmpp/bower.json | 11 + .../Strophe.js}/strophe.js | 680 +- .../bower_components/backbone/backbone.js | 1571 ++ .../bower_components/jquery/jquery.js | 8755 +++++++ .../bower_components/lodash/lodash.js | 5557 +++++ .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../backbone.xmpp/index.html | 139 +- .../backbone.xmpp/{README.md => readme.md} | 0 .../backbone_marionette/.jshintignore | 1 - .../backbone_marionette/README.md | 28 - .../backbone_marionette/bower.json | 7 +- .../backbone.localStorage.js | 60 +- .../lib/backbone.marionette.js | 1143 +- .../bower_components/backbone/backbone.js | 1083 +- .../bower_components/jquery/jquery.js | 8586 +++---- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- .../backbone_marionette/index.html | 12 +- .../backbone_marionette/js/TodoMVC.Layout.js | 50 +- .../js/TodoMVC.TodoList.Views.js | 9 +- .../js/TodoMVC.TodoList.js | 2 +- .../backbone_marionette/readme.md | 35 + .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- labs/architecture-examples/batman/index.html | 132 +- labs/architecture-examples/batman/readme.md | 41 +- labs/architecture-examples/cujo/README.md | 34 - labs/architecture-examples/cujo/TODO.md | 2 - .../cujo/app/controller.js | 78 +- .../cujo/app/controls/strings.js | 2 +- .../cujo/app/controls/structure.css | 21 +- .../cujo/app/controls/template.html | 13 - .../cujo/app/create/cleanTodo.js | 9 +- .../cujo/app/create/generateMetadata.js | 32 +- .../cujo/app/create/strings.js | 1 + .../cujo/app/create/validateTodo.js | 17 +- .../cujo/app/footer/strings.js | 1 + .../cujo/app/footer/template.html | 3 +- .../cujo/app/list/setCompletedClass.js | 7 +- .../cujo/app/list/strings.js | 1 + .../cujo/app/list/structure.css | 8 +- .../cujo/app/list/template.html | 2 +- labs/architecture-examples/cujo/app/main.js | 52 +- labs/architecture-examples/cujo/app/run.js | 38 +- labs/architecture-examples/cujo/bower.json | 13 + .../cujo/bower_components/cola/Collection.js | 110 + .../cujo/bower_components/cola/Model.js | 34 + .../cola/SortedMap.js | 0 .../cola/adapter/Array.js | 0 .../cola/adapter/LocalStorage.js | 0 .../cola/adapter/Object.js | 24 +- .../cola/adapter/ObjectToArray.js | 0 .../cola/adapter/Query.js | 0 .../cola/adapter/makeJoined.js | 0 .../cola/adapter/makeTransformed.js | 2 +- .../cola/adapter/makeTransformedProperties.js | 0 .../bower_components/cola/adapterResolver.js | 43 + .../{lib => bower_components}/cola/cola.js | 25 +- .../cola/collectionAdapterResolver.js | 19 + .../cola/comparator/byProperty.js | 2 +- .../cola/comparator/compose.js | 0 .../cola/comparator/naturalOrder.js | 2 +- .../cola/comparator/reverse.js | 0 .../cola/dom/adapter/Node.js | 43 +- .../cola/dom/adapter/NodeList.js | 35 +- .../cola/dom/bindingHandler.js | 36 +- .../cola/dom/classList.js | 38 + .../cola/dom/events.js | 2 +- .../cujo/bower_components/cola/dom/form.js | 200 + .../cola/dom/formElementFinder.js | 2 +- .../cola/dom/guess.js | 6 +- .../{lib => bower_components}/cola/dom/has.js | 2 +- .../{lib => bower_components}/cola/enqueue.js | 0 .../cujo/bower_components/cola/hub/Base.js | 334 + .../cola/hub/eventProcessor.js | 90 + .../cola/identifier/default.js | 2 +- .../cola/identifier/property.js | 2 +- .../cola/network/strategy/base.js | 2 +- .../cola/network/strategy/changeEvent.js | 2 +- .../network/strategy/collectThenDeliver.js | 2 +- .../cola/network/strategy/compose.js | 10 +- .../cola/network/strategy/default.js | 2 +- .../cola/network/strategy/defaultModel.js | 52 + .../cola/network/strategy/minimal.js | 2 +- .../cola/network/strategy/syncAfterJoin.js | 2 +- .../cola/network/strategy/syncDataDirectly.js | 2 +- .../cola/network/strategy/syncModel.js | 115 + .../cola/network/strategy/targetFirstItem.js | 2 +- .../cola/network/strategy/validate.js | 2 +- .../cola/objectAdapterResolver.js | 18 + .../cola/projection/assign.js | 2 +- .../cola/projection/inherit.js | 2 +- .../cola/relational/hashJoin.js | 0 .../cola/relational/propertiesKey.js | 2 +- .../cola/relational/strategy/leftOuterJoin.js | 0 .../cola/transform/compose.js | 0 .../cola/transform/configure.js | 2 +- .../cola/transform/createEnum.js | 2 +- .../cola/transform/expression.js | 2 +- .../cola/validation/composeValidators.js | 2 +- .../validation/form/formValidationHandler.js | 0 .../curl/src/curl.js | 701 +- .../curl/src/curl/debug.js | 9 +- .../curl/src/curl/domReady.js | 2 +- .../curl/src/curl/loader/cjsm11.js | 83 + .../curl/src/curl/plugin/README.md | 0 .../curl/src/curl/plugin/_fetchText.js | 52 + .../curl/src/curl/plugin/async.js | 30 +- .../curl/src/curl/plugin/css.js | 580 + .../curl/src/curl/plugin/domReady.js | 4 +- .../curl/src/curl/plugin/i18n.js | 196 + .../curl/src/curl/plugin/js.js | 55 +- .../curl/src/curl/plugin/json.js | 68 + .../curl/src/curl/plugin/link.js | 6 +- .../curl/src/curl/plugin/style.js | 147 + .../curl/src/curl/plugin/text.js | 38 + .../curl/src/curl/shim/dojo16.js | 2 +- .../curl/src/curl/shim/ssjs.js | 14 +- .../curl/src/curl/tdd/runner.js | 11 +- .../curl/src/curl/tdd/undefine.js | 2 +- .../bower_components/meld/aspect/cache.js | 50 + .../bower_components/meld/aspect/memoize.js | 36 + .../bower_components/meld/aspect/trace.js | 84 + .../cujo/bower_components/meld/meld.js | 598 + .../cujo/bower_components/poly/all.js | 20 + .../{lib => bower_components}/poly/array.js | 2 +- .../cujo/bower_components/poly/date.js | 216 + .../cujo/bower_components/poly/es5-strict.js | 32 + .../cujo/bower_components/poly/es5.js | 20 + .../poly/function.js | 2 +- .../cujo/bower_components/poly/json.js | 14 + .../poly/lib/_base.js | 6 +- .../{lib => bower_components}/poly/object.js | 125 +- .../{lib => bower_components}/poly/poly.js | 11 +- .../bower_components/poly/setImmediate.js | 220 + .../cujo/bower_components/poly/strict.js | 35 + .../{lib => bower_components}/poly/string.js | 52 +- .../bower_components/poly/support/json3.js | 783 + .../cujo/bower_components/poly/xhr.js | 39 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../{lib => bower_components}/when/apply.js | 16 +- .../cujo/bower_components/when/callbacks.js | 248 + .../when/cancelable.js | 28 +- .../cujo/bower_components/when/debug.js | 382 + .../cujo/bower_components/when/delay.js | 54 + .../cujo/bower_components/when/function.js | 202 + .../cujo/bower_components/when/guard.js | 76 + .../cujo/bower_components/when/keys.js | 99 + .../bower_components/when/node/function.js | 180 + .../cujo/bower_components/when/parallel.js | 43 + .../cujo/bower_components/when/pipeline.js | 54 + .../cujo/bower_components/when/poll.js | 131 + .../cujo/bower_components/when/sequence.js | 50 + .../{lib => bower_components}/when/timed.js | 17 +- .../cujo/bower_components/when/timeout.js | 73 + .../cujo/bower_components/when/unfold.js | 46 + .../cujo/bower_components/when/unfold/list.js | 41 + .../cujo/bower_components/when/when.js | 822 + .../cujo/bower_components/wire/aop.js | 265 + .../bower_components/wire/builder/cram.js | 238 + .../cujo/bower_components/wire/connect.js | 99 + .../cujo/bower_components/wire/debug.js | 565 + .../wire/dojo/data.js | 37 +- .../wire/dojo/dijit.js | 79 +- .../wire/dojo/dom.js | 2 +- .../wire/dojo/events.js | 26 +- .../{lib => bower_components}/wire/dojo/on.js | 6 +- .../wire/dojo/pubsub.js | 26 +- .../wire/dojo/store.js | 10 +- .../{lib => bower_components}/wire/dom.js | 4 +- .../wire/dom/render.js | 76 +- .../wire/dom/transform/cardinality.js | 2 +- .../wire/dom/transform/mapClasses.js | 8 +- .../wire/dom/transform/mapTokenList.js | 46 + .../wire/dom/transform/replaceClasses.js | 15 +- .../wire/dom/transform/toggleClasses.js | 5 +- .../wire/domReady.js | 13 +- .../wire/jquery/dom.js | 0 .../wire/jquery/on.js | 6 +- .../cujo/bower_components/wire/jquery/ui.js | 221 + .../wire/lib/ComponentFactory.js | 166 + .../bower_components/wire/lib/Container.js | 174 + .../bower_components/wire/lib/WireContext.js | 34 + .../bower_components/wire/lib/WireProxy.js | 200 + .../cujo/bower_components/wire/lib/advice.js | 82 + .../wire/lib/array.js | 31 +- .../wire/lib/connection.js | 57 +- .../cujo/bower_components/wire/lib/context.js | 51 + .../wire/lib/dom/base.js | 128 +- .../wire/lib/functional.js | 112 +- .../wire/lib/graph/DirectedGraph.js | 95 + .../wire/lib/graph/formatCycles.js | 24 + .../bower_components/wire/lib/graph/tarjan.js | 112 + .../wire/lib/graph/trackInflightRefs.js | 91 + .../wire/lib/instantiate.js} | 21 +- .../cujo/bower_components/wire/lib/invoker.js | 11 + .../bower_components/wire/lib/lifecycle.js | 124 + .../cujo/bower_components/wire/lib/loader.js | 74 + .../wire/lib/object.js | 31 +- .../wire/lib/plugin-base/dom.js | 153 +- .../wire/lib/plugin-base/on.js | 234 +- .../wire/lib/plugin/basePlugin.js | 321 + .../wire/lib/plugin/defaultPlugins.js | 14 + .../wire/lib/plugin/priority.js | 40 + .../wire/lib/plugin/registry.js | 137 + .../wire/lib/plugin/wirePlugin.js | 123 + .../bower_components/wire/lib/resolver.js | 121 + .../cujo/bower_components/wire/lib/scope.js | 433 + .../cujo/{lib => bower_components}/wire/on.js | 6 +- .../{lib => bower_components}/wire/sizzle.js | 0 .../{lib => bower_components}/wire/wire.js | 63 +- labs/architecture-examples/cujo/index.html | 28 +- .../cujo/lib/aop/LICENSE.txt | 24 - .../cujo/lib/aop/README.md | 42 - .../architecture-examples/cujo/lib/aop/aop.js | 370 - .../cujo/lib/aop/package.json | 33 - .../cujo/lib/cola/AdapterResolver.js | 44 - .../cujo/lib/cola/Hub.js | 471 - .../cujo/lib/cola/demo/ArrayToNodeList.html | 167 - .../cujo/lib/cola/doc/ICollectionAdapter.js | 116 - .../cujo/lib/cola/doc/IObjectAdapter.js | 35 - .../cujo/lib/cola/dom/formToObject.js | 82 - .../cujo/lib/cola/package.json | 48 - .../cujo/lib/curl/.gitmodules | 0 .../cujo/lib/curl/LICENSE.txt | 24 - .../cujo/lib/curl/README.md | 802 - .../cujo/lib/curl/package.json | 33 - .../cujo/lib/curl/src/curl/loader/cjsm11.js | 118 - .../lib/curl/src/curl/plugin/builder/css.js | 76 - .../lib/curl/src/curl/plugin/builder/text.js | 56 - .../cujo/lib/curl/src/curl/plugin/css.js | 455 - .../cujo/lib/curl/src/curl/plugin/i18n.js | 28 - .../cujo/lib/curl/src/curl/plugin/text.js | 81 - .../cujo/lib/poly/LICENSE.txt | 24 - .../cujo/lib/poly/README.md | 202 - .../cujo/lib/poly/all.js | 7 - .../cujo/lib/poly/json.js | 16 - .../cujo/lib/poly/lib/_async.js | 48 - .../cujo/lib/poly/lib/_json.js | 54 - .../cujo/lib/poly/package.json | 39 - .../cujo/lib/poly/support/json2.js | 489 - .../cujo/lib/poly/xhr.js | 42 - .../cujo/lib/when/.travis.yml | 6 - .../cujo/lib/when/LICENSE.txt | 24 - .../cujo/lib/when/README.md | 319 - .../cujo/lib/when/debug.js | 261 - .../cujo/lib/when/delay.js | 59 - .../cujo/lib/when/package.json | 39 - .../cujo/lib/when/timeout.js | 73 - .../cujo/lib/when/when.js | 771 - .../cujo/lib/wire/LICENSE.txt | 24 - .../cujo/lib/wire/README.md | 176 - .../cujo/lib/wire/aop.js | 258 - .../cujo/lib/wire/base.js | 387 - .../cujo/lib/wire/connect.js | 113 - .../cujo/lib/wire/cram/builder.js | 119 - .../cujo/lib/wire/debug.js | 517 - .../lib/wire/dom/transform/mapTokenList.js | 32 - .../cujo/lib/wire/lib/context.js | 917 - .../cujo/lib/wire/lib/lifecycle.js | 120 - .../cujo/lib/wire/lib/moduleLoader.js | 34 - .../cujo/lib/wire/lib/resolver.js | 81 - .../cujo/lib/wire/package.json | 52 - labs/architecture-examples/cujo/readme.md | 56 + .../architecture-examples/cujo/theme/base.css | 10 +- labs/architecture-examples/derby/README.md | 31 - .../public/components/todomvc-common/base.css | 143 +- .../public/components/todomvc-common/base.js | 211 +- labs/architecture-examples/derby/readme.md | 65 + .../derby/views/todos/index.html | 2 +- labs/architecture-examples/dermis/README.md | 9 - labs/architecture-examples/dermis/bower.json | 9 + .../dermis/bower_components/jquery/jquery.js | 8755 +++++++ .../bower_components/requirejs/require.js | 2045 ++ .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes labs/architecture-examples/dermis/index.html | 123 +- labs/architecture-examples/dermis/readme.md | 26 + labs/architecture-examples/dijon/bower.json | 9 + .../handlebars.js/handlebars.js | 2201 ++ .../dijon/bower_components/jquery/jquery.js | 8755 +++++++ .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes labs/architecture-examples/dijon/index.html | 107 +- labs/architecture-examples/dijon/readme.md | 25 +- labs/architecture-examples/duel/.bowerrc | 3 + labs/architecture-examples/duel/bower.json | 7 + labs/architecture-examples/duel/readme.md | 48 +- .../src/main/resources/views/HomePage.duel | 10 +- .../duel/src/main/resources/views/Task.duel | 2 +- .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../duel/src/main/webapp/css/base.css | 389 - .../duel/src/main/webapp/css/styles.merge | 7 +- .../duel/src/main/webapp/js/scripts.merge | 3 + .../src/main/webapp/js/todos/controller.js | 138 +- .../duel/src/main/webapp/js/todos/model.js | 133 +- ...40176df828f72a94b201a48c223860b95908dc.js} | 21 +- ...2117dcda6b1a71004e818c348c9de5fc80966a.css | 1 - ...64469b1882372019d07f8c1174b1d64507e56d.css | 1 + .../architecture-examples/duel/www/index.html | 37 +- labs/architecture-examples/epitome/bower.json | 8 + .../bower_components/Epitome/Epitome-min.js | 1 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes labs/architecture-examples/epitome/index.html | 131 +- labs/architecture-examples/epitome/js/app.js | 30 +- .../epitome/js/collections/todo-collection.js | 8 +- .../epitome/js/controllers/todo-router.js | 10 +- .../epitome/js/lib/Epitome-min.js | 1 - .../epitome/js/models/todo-model.js | 4 +- .../epitome/js/views/todo-list.js | 66 +- .../epitome/js/views/todo-main.js | 73 +- labs/architecture-examples/epitome/readme.md | 24 +- labs/architecture-examples/extjs/bower.json | 7 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes labs/architecture-examples/extjs/css/app.css | 244 +- labs/architecture-examples/extjs/index.html | 53 +- labs/architecture-examples/extjs/readme.md | 23 + .../extjs_deftjs/bower.json | 7 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../extjs_deftjs/css/app.css | 10 +- .../extjs_deftjs/index.html | 42 +- .../extjs_deftjs/{README.md => readme.md} | 27 +- .../firebase-angular/bower.json | 12 + .../angular-fire/angularFire.js | 515 + .../bower_components/angular-fire/bower.json | 26 + .../angular-mocks/angular-mocks.js | 1788 ++ .../bower_components/angular-mocks/bower.json | 17 + .../bower_components/angular/angular.js | 14847 +++++++++++ .../bower_components/angular/angular.min.js | 163 + .../bower_components/angular/bower.json | 14 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../firebase-angular/index.html | 72 + .../firebase-angular/js/app.js | 31 + .../js/controllers/todoCtrl.js | 88 + .../js/directives/todoBlur.js | 13 + .../js/directives/todoEscape.js | 18 + .../js/directives/todoFocus.js | 17 + .../firebase-angular/readme.md | 40 + labs/architecture-examples/kendo/bower.json | 8 + .../kendo/bower_components/jquery/jquery.js | 8755 +++++++ .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes labs/architecture-examples/kendo/index.html | 129 +- labs/architecture-examples/kendo/readme.md | 27 + .../bower.json | 9 + .../director/build/director.js | 712 + .../bower_components/knockout.js/knockout.js | 85 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../index.html | 13 +- .../js/lib/knockout.min.js | 86 - .../knockoutjs_classBindingProvider/readme.md | 37 +- labs/architecture-examples/meteor/.bowerrc | 3 + .../meteor/.meteor/packages | 2 +- .../meteor/.meteor/release | 1 + labs/architecture-examples/meteor/app.html | 11 +- labs/architecture-examples/meteor/app.js | 35 +- labs/architecture-examples/meteor/bower.json | 8 + .../director/build/director.js | 712 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../meteor/client/lib/base.js | 7 - .../meteor/client/lib/director-1.1.3.min.js | 7 - .../meteor/client/lib/ie.js | 25 - labs/architecture-examples/meteor/readme.md | 62 +- labs/architecture-examples/montage/bower.json | 7 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes labs/architecture-examples/montage/index.html | 20 +- labs/architecture-examples/montage/readme.md | 48 +- .../montage/ui/main.reel/main.html | 2 +- .../montage/ui/todo-view.reel/todo-view.html | 2 +- labs/architecture-examples/o_O/index.html | 59 - labs/architecture-examples/o_O/js/app.js | 182 - labs/architecture-examples/o_O/js/lib/o_O.js | 20 - .../o_O/js/lib/o_O.router.js | 3 - .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- labs/architecture-examples/olives/index.html | 96 +- labs/architecture-examples/olives/readme.md | 18 +- .../plastronjs/bower.json | 7 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../plastronjs/index.html | 100 +- .../plastronjs/readme.md | 61 +- labs/architecture-examples/polymer/index.html | 8 + labs/architecture-examples/puremvc/README.md | 23 - .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- labs/architecture-examples/puremvc/index.html | 4 +- labs/architecture-examples/puremvc/readme.md | 39 + .../rappidjs/app/TodoClass.js | 70 +- .../rappidjs/app/collection/TodoList.js | 78 +- .../rappidjs/app/model/Todo.js | 14 +- .../rappidjs/app/view/TodoView.xml | 37 +- .../architecture-examples/rappidjs/bower.json | 7 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../architecture-examples/rappidjs/index.html | 48 +- labs/architecture-examples/rappidjs/readme.md | 24 + labs/architecture-examples/react/bower.json | 9 + .../bower_components/director/.bower.json | 13 + .../bower_components/director/.gitignore | 6 + .../bower_components/director/.travis.yml | 12 + .../react/bower_components/director/LICENSE | 19 + .../react/bower_components/director/README.md | 822 + .../react/bower_components/director/bin/build | 79 + .../director/build/director.js | 712 + .../director/build/director.min.js | 7 + .../bower_components/director/build/ender.js | 3 + .../director/examples/http.js | 33 + .../director/img/director.png | Bin 0 -> 12856 bytes .../director/img/hashRoute.png | Bin 0 -> 12485 bytes .../bower_components/director/lib/director.js | 6 + .../director/lib/director/browser.js | 297 + .../director/lib/director/cli.js | 65 + .../director/lib/director/http/index.js | 251 + .../director/lib/director/http/methods.js | 66 + .../director/lib/director/http/responses.js | 93 + .../director/lib/director/router.js | 797 + .../bower_components/director/package.json | 42 + .../director/test/browser/backend/backend.js | 71 + .../test/browser/browserify-harness.html | 24 + .../director/test/browser/helpers/api.js | 77 + .../test/browser/html5-routes-harness.html | 23 + .../test/browser/html5-routes-test.js | 660 + .../director/test/browser/routes-harness.html | 21 + .../director/test/browser/routes-test.js | 694 + .../director/test/server/cli/dispatch-test.js | 55 + .../director/test/server/cli/mount-test.js | 30 + .../director/test/server/cli/path-test.js | 39 + .../test/server/core/dispatch-test.js | 113 + .../director/test/server/core/insert-test.js | 45 + .../director/test/server/core/mount-test.js | 117 + .../director/test/server/core/on-test.js | 38 + .../director/test/server/core/path-test.js | 49 + .../test/server/core/regifystring-test.js | 103 + .../director/test/server/helpers/index.js | 52 + .../director/test/server/helpers/macros.js | 55 + .../director/test/server/http/accept-test.js | 88 + .../director/test/server/http/attach-test.js | 51 + .../director/test/server/http/before-test.js | 38 + .../director/test/server/http/http-test.js | 65 + .../director/test/server/http/methods-test.js | 42 + .../test/server/http/responses-test.js | 21 + .../director/test/server/http/stream-test.js | 46 + .../react/bower_components/react/.bower.json | 14 + .../bower_components/react/JSXTransformer.js | 10196 ++++++++ .../react/bower_components/react/bower.json | 5 + .../react/bower_components/react/react.js | 11328 +++++++++ .../react/bower_components/react/react.min.js | 20 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes labs/architecture-examples/react/index.html | 24 + labs/architecture-examples/react/js/app.jsx | 207 + .../architecture-examples/react/js/footer.jsx | 58 + .../react/js/todoItem.jsx | 93 + labs/architecture-examples/react/js/utils.jsx | 49 + labs/architecture-examples/react/readme.md | 38 + .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- labs/architecture-examples/sammyjs/index.html | 4 +- labs/architecture-examples/sammyjs/readme.md | 35 +- labs/architecture-examples/sapui5/bower.json | 7 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../architecture-examples/sapui5/css/base.css | 553 + labs/architecture-examples/sapui5/img/bg.png | Bin 0 -> 2126 bytes labs/architecture-examples/sapui5/index.html | 30 + labs/architecture-examples/sapui5/js/app.js | 19 + .../sapui5/js/todo/SmartTextField.js | 68 + .../sapui5/js/todo/Todo.controller.js | 137 + .../sapui5/js/todo/Todo.view.js | 172 + .../sapui5/js/todo/TodoPersistency.js | 33 + .../sapui5/js/todo/formatters.js | 64 + .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- .../serenadejs/index.html | 112 +- .../serenadejs/readme.md | 34 +- .../socketstream/README.md | 12 - .../client/code/libs/todomvc-common/base.css | 143 +- .../client/code/libs/todomvc-common/base.js | 211 +- .../socketstream/client/views/app.html | 4 +- .../socketstream/package.json | 5 +- .../socketstream/readme.md | 37 + labs/architecture-examples/somajs/bower.json | 10 + .../director/build/director.js | 712 + .../soma-template/build/soma-template.js | 1377 ++ .../bower_components/soma.js/build/soma.js | 908 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../{rappidjs => somajs}/css/app.css | 4 +- labs/architecture-examples/somajs/index.html | 124 +- labs/architecture-examples/somajs/js/app.js | 42 +- .../somajs/js/lib/soma-native_v1.0.2_min.js | 1 - .../somajs/js/models/router.js | 23 + .../somajs/js/models/todos.js | 27 + .../js/todos/controllers/controllers.js | 55 - .../somajs/js/todos/models/models.js | 117 - .../somajs/js/todos/views/views.js | 121 - .../somajs/js/views/footer.js | 43 + .../somajs/js/views/header.js | 44 + .../somajs/js/views/main.js | 89 + labs/architecture-examples/somajs/readme.md | 30 +- labs/architecture-examples/stapes/bower.json | 10 + .../handlebars.js/handlebars.js | 2201 ++ .../stapes/bower_components/jquery/jquery.js | 8755 +++++++ .../stapes/bower_components/stapes/stapes.js | 388 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes labs/architecture-examples/stapes/index.html | 118 +- .../stapes/js/lib/stapes.js | 24 - labs/architecture-examples/stapes/readme.md | 18 + labs/architecture-examples/thorax/bower.json | 8 + .../bower_components}/backbone/backbone.js | 0 .../handlebars.js/handlebars.js | 2239 ++ .../thorax/bower_components/jquery/jquery.js | 8755 +++++++ .../thorax/bower_components/thorax/thorax.js | 2670 ++ .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../underscore}/underscore.js | 733 +- labs/architecture-examples/thorax/index.html | 152 +- .../thorax/js/lib/thorax.js | 16884 ------------- .../thorax/{README.md => readme.md} | 36 +- .../typescript-angular/ReadMe.md | 64 - .../typescript-angular/bower.json | 8 + .../bower_components/angular/angular.js | 14733 +++++++++++ .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../typescript-angular/index.html | 142 +- .../typescript-angular/readme.md | 83 + .../typescript-backbone/bower.json | 9 + .../bower_components/backbone/backbone.js | 1571 ++ .../bower_components/jquery/jquery.js | 8755 +++++++ .../bower_components/lodash/lodash.js | 5557 +++++ .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../typescript-backbone/index.html | 20 +- .../typescript-backbone/readme.md | 97 +- .../angularjs_require/bower.json | 2 +- .../bower_components/angular/angular.js | 602 +- .../bower_components/todomvc-common/base.css | 143 +- .../bower_components/todomvc-common/base.js | 209 +- .../angularjs_require/index.html | 134 +- .../angularjs_require/js/controllers/todo.js | 9 +- .../angularjs_require/readme.md | 36 + .../backbone_marionette_require/.jshintignore | 9 - .../backbone_marionette_require/app.build.js | 46 +- .../backbone_marionette_require/bower.json | 11 + .../backbone.localStorage.js | 220 + .../lib/backbone.marionette.js | 2358 ++ .../bower_components/backbone/backbone.js | 1571 ++ .../bower_components/jquery/jquery.js | 5919 ++--- .../bower_components/requirejs/require.js | 2045 ++ .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../bower_components/underscore/underscore.js | 1226 + .../css/custom.css | 14 +- .../index-dev.html | 38 - .../backbone_marionette_require/index.html | 60 +- .../backbone_marionette_require/js/app.js | 109 +- .../js/collections/TodoList.js | 42 +- .../js/controllers/index.js | 18 +- .../js/lib/backbone-localStorage.js | 136 - .../js/lib/backbone.js | 1431 -- .../js/lib/backbone.marionette.js | 1346 - .../js/lib/require.js | 35 - .../js/main.built.js | 180 - .../backbone_marionette_require/js/main.js | 67 +- .../js/models/Todo.js | 40 +- .../js/routers/index.js | 17 +- .../js/templates.js | 18 +- .../js/templates/footer.tmpl | 22 +- .../js/templates/todoItemView.tmpl | 6 +- .../backbone_marionette_require/js/vent.js | 4 - .../js/views/ActiveCount.js | 31 +- .../js/views/CompletedCount.js | 24 + .../js/views/Footer.js | 70 +- .../js/views/Header.js | 50 +- .../js/views/TodoItemView.js | 135 +- .../js/views/TodoListCompositeView.js | 88 +- .../backbone_marionette_require/r.js | 15483 ------------ .../backbone_marionette_require/readme.md | 35 + .../canjs_require/bower.json | 9 + .../bower_components/CanJS/amd/can.js | 9 + .../CanJS/amd/can/construct.js | 178 + .../CanJS/amd/can/construct/proxy.js | 68 + .../CanJS/amd/can/construct/super.js | 48 + .../bower_components/CanJS/amd/can/control.js | 270 + .../CanJS/amd/can/control/plugin.js | 108 + .../CanJS/amd/can/control/route.js | 36 + .../bower_components/CanJS/amd/can/model.js | 428 + .../bower_components/CanJS/amd/can/observe.js | 660 + .../CanJS/amd/can/observe/attributes.js | 160 + .../CanJS/amd/can/observe/backup.js | 45 + .../CanJS/amd/can/observe/compute.js | 220 + .../CanJS/amd/can/observe/delegate.js | 205 + .../CanJS/amd/can/observe/list.js | 106 + .../CanJS/amd/can/observe/setter.js | 59 + .../CanJS/amd/can/observe/validations.js | 197 + .../bower_components/CanJS/amd/can/route.js | 321 + .../CanJS/amd/can/util/array/each.js | 35 + .../CanJS/amd/can/util/can.js | 29 + .../CanJS/amd/can/util/deferred.js | 174 + .../CanJS/amd/can/util/dojo.js | 526 + .../CanJS/amd/can/util/event.js | 62 + .../CanJS/amd/can/util/fixture.js | 614 + .../CanJS/amd/can/util/fragment.js | 68 + .../CanJS/amd/can/util/hashchange.js | 27 + .../CanJS/amd/can/util/jquery.js | 73 + .../CanJS/amd}/can/util/library.js | 8 +- .../CanJS/amd/can/util/mootools.js | 362 + .../CanJS/amd/can/util/object.js | 133 + .../CanJS/amd/can/util/object/isplain.js | 40 + .../CanJS/amd/can/util/string.js | 130 + .../CanJS/amd/can/util/string/deparam.js | 61 + .../CanJS/amd/can/util/yui.js | 391 + .../CanJS/amd/can/util/zepto.js | 233 + .../bower_components/CanJS/amd/can/view.js | 409 + .../CanJS/amd/can/view/ejs.js | 99 + .../CanJS/amd/can/view/modifiers.js | 158 + .../CanJS/amd/can/view/mustache.js | 855 + .../CanJS/amd/can/view/render.js | 475 + .../CanJS/amd/can/view/scanner.js | 443 + .../bower_components/jquery/jquery.js | 9597 ++++++++ .../bower_components/requirejs/require.js | 2045 ++ .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../canjs_require/index.html | 39 +- .../canjs_require/js/app.js | 66 +- .../js/{app => controls}/todos.js | 14 +- .../canjs_require/js/lib/can.js | 9 - .../canjs_require/js/lib/can/construct.js | 178 - .../js/lib/can/construct/proxy.js | 68 - .../js/lib/can/construct/super.js | 48 - .../canjs_require/js/lib/can/control.js | 270 - .../js/lib/can/control/plugin.js | 108 - .../canjs_require/js/lib/can/control/route.js | 36 - .../canjs_require/js/lib/can/model.js | 405 - .../canjs_require/js/lib/can/observe.js | 650 - .../js/lib/can/observe/attributes.js | 154 - .../js/lib/can/observe/backup.js | 45 - .../js/lib/can/observe/compute.js | 210 - .../js/lib/can/observe/delegate.js | 205 - .../canjs_require/js/lib/can/observe/list.js | 106 - .../js/lib/can/observe/setter.js | 59 - .../js/lib/can/observe/validations.js | 198 - .../canjs_require/js/lib/can/route.js | 315 - .../js/lib/can/util/array/each.js | 35 - .../canjs_require/js/lib/can/util/can.js | 20 - .../canjs_require/js/lib/can/util/deferred.js | 174 - .../canjs_require/js/lib/can/util/dojo.js | 526 - .../canjs_require/js/lib/can/util/event.js | 62 - .../canjs_require/js/lib/can/util/fixture.js | 603 - .../canjs_require/js/lib/can/util/fragment.js | 68 - .../canjs_require/js/lib/can/util/jquery.js | 63 - .../canjs_require/js/lib/can/util/mootools.js | 288 - .../canjs_require/js/lib/can/util/object.js | 133 - .../js/lib/can/util/object/extend.js | 75 - .../js/lib/can/util/object/isplain.js | 40 - .../canjs_require/js/lib/can/util/string.js | 130 - .../js/lib/can/util/string/deparam.js | 59 - .../canjs_require/js/lib/can/util/yui.js | 389 - .../canjs_require/js/lib/can/util/zepto.js | 233 - .../canjs_require/js/lib/can/view.js | 397 - .../canjs_require/js/lib/can/view/ejs.js | 99 - .../js/lib/can/view/modifiers.js | 158 - .../canjs_require/js/lib/can/view/mustache.js | 772 - .../canjs_require/js/lib/can/view/render.js | 457 - .../canjs_require/js/lib/can/view/scanner.js | 436 - .../js/{app => }/models/localstorage.js | 26 +- .../canjs_require/js/{app => }/models/todo.js | 17 +- .../canjs_require/readme.md | 95 +- .../chaplin-brunch/.gitignore | 3 + .../chaplin-brunch/README.md | 15 - .../chaplin-brunch/app/application.coffee | 52 +- .../chaplin-brunch/app/assets/index.html | 59 +- .../app/controllers/base/controller.coffee | 3 - .../app/controllers/footer-controller.coffee | 8 - .../app/controllers/header-controller.coffee | 8 - .../app/controllers/index-controller.coffee | 28 +- .../app/controllers/todos-controller.coffee | 8 - .../chaplin-brunch/app/initialize.coffee | 5 +- .../chaplin-brunch/app/lib/support.coffee | 13 - .../chaplin-brunch/app/lib/utils.coffee | 12 - .../chaplin-brunch/app/lib/view-helper.coffee | 39 - .../chaplin-brunch/app/mediator.coffee | 2 +- .../app/models/base/collection.coffee | 9 - .../app/models/base/model.coffee | 5 - .../chaplin-brunch/app/models/todo.coffee | 8 +- .../chaplin-brunch/app/models/todos.coffee | 3 +- .../app/views/base/collection-view.coffee | 2 +- .../chaplin-brunch/app/views/base/view.coffee | 3 - .../app/views/footer-view.coffee | 23 +- .../app/views/header-view.coffee | 24 +- .../chaplin-brunch/app/views/layout.coffee | 10 - .../chaplin-brunch/app/views/todo-view.coffee | 30 +- .../app/views/todos-view.coffee | 19 +- .../chaplin-brunch/bower.json | 26 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../chaplin-brunch/config.coffee | 24 +- .../chaplin-brunch/package.json | 14 +- .../chaplin-brunch/public/app.js | 15442 ++++++++++++ .../chaplin-brunch/public/app.js.map | 1 + .../chaplin-brunch/public/index.html | 59 +- .../chaplin-brunch/public/javascripts/app.js | 937 - .../public/javascripts/vendor.js | 3855 --- .../chaplin-brunch/public/stylesheets/app.css | 5 - .../chaplin-brunch/readme.md | 60 + .../vendor/scripts/backbone-localStorage.js | 136 - .../vendor/scripts/chaplin-0.5.0.coffee | 2249 -- .../vendor/scripts/console-helper.js | 11 - labs/dependency-examples/durandal/bower.json | 12 + .../bower_components/durandal/amd/require.js | 35 + .../bower_components/durandal/amd/text.js | 308 + .../durandal/bower_components/durandal/app.js | 61 + .../bower_components/durandal/composition.js | 294 + .../bower_components/durandal/events.js | 139 + .../bower_components/durandal/modalDialog.js | 166 + .../durandal/plugins/router.js | 386 + .../bower_components/durandal/system.js | 165 + .../bower_components/durandal/viewEngine.js | 67 + .../bower_components/durandal/viewLocator.js | 103 + .../bower_components/durandal/viewModel.js | 445 + .../durandal/viewModelBinder.js | 76 + .../bower_components/durandal/widget.js | 131 + .../bower_components/jquery/jquery.js | 9597 ++++++++ .../bower_components/knockout/knockout.js | 85 + .../bower_components/requirejs/require.js | 35 + .../durandal/bower_components/sammy/sammy.js | 2120 ++ .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes labs/dependency-examples/durandal/css/app.css | 52 + labs/dependency-examples/durandal/index.html | 21 + labs/dependency-examples/durandal/js/main.js | 107 + .../durandal/js/viewmodels/entry.js | 24 + .../durandal/js/viewmodels/list.js | 155 + .../durandal/js/viewmodels/shell.js | 15 + .../durandal/js/viewmodels/todoapp.js | 17 + .../durandal/js/views/entry.html | 4 + .../durandal/js/views/list.html | 36 + .../durandal/js/views/shell.html | 14 + .../durandal/js/views/todoapp.html | 11 + labs/dependency-examples/durandal/readme.md | 34 + .../bower_components/todomvc-common/base.css | 149 +- .../bower_components/todomvc-common/base.js | 211 +- .../enyo_backbone/index.html | 19 +- .../enyo_backbone/js/start.js | 5 +- .../enyo_backbone/js/views/WindowView.js | 2 +- .../enyo_backbone/readme.md | 28 + .../knockoutjs_require/README.md | 3 - .../knockoutjs_require/bower.json | 9 + .../bower_components/knockout.js/knockout.js | 85 + .../bower_components/requirejs/require.js | 2045 ++ .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../knockoutjs_require/index.html | 101 +- .../knockoutjs_require/js/config/global.js | 6 +- .../knockoutjs_require/js/extends/handlers.js | 84 +- .../knockoutjs_require/js/extends/native.js | 9 - .../js/libs/knockout-2.1.0.debug.js | 3443 --- .../js/libs/knockout-2.1.0.js | 86 - .../knockoutjs_require/js/main.js | 33 +- .../knockoutjs_require/js/models/Todo.js | 24 +- .../knockoutjs_require/js/viewmodels/todo.js | 193 +- .../knockoutjs_require/readme.md | 36 + .../somajs_require/bower.json | 11 + .../director/build/director.js | 712 + .../bower_components/requirejs/require.js | 0 .../soma-template/build/soma-template.js | 1377 ++ .../bower_components/soma.js/build/soma.js | 908 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../somajs_require/css/app.css | 3 + .../somajs_require/index.html | 64 + .../somajs_require/js/app.js | 60 + .../somajs_require/js/models/router.js | 29 + .../somajs_require/js/models/todos.js | 35 + .../somajs_require/js/views/footer.js | 50 + .../somajs_require/js/views/header.js | 52 + .../somajs_require/js/views/main.js | 96 + .../somajs_require/readme.md | 46 + .../stapes_require/bower.json | 11 + .../handlebars.js/handlebars.js | 2201 ++ .../bower_components/requirejs/require.js | 2045 ++ .../bower_components/stapes/stapes.js | 388 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../bower_components/zepto/zepto.js | 1589 ++ .../stapes_require/index.html | 106 +- .../stapes_require/js/app.js | 15 +- .../js/controllers/todoController.js | 2 +- .../stapes_require/js/lib/.gitignore | 1 - .../stapes_require/js/lib/require.js | 33 - .../stapes_require/js/lib/stapes.js | 24 - .../stapes_require/js/lib/zepto.js | 2 - .../stapes_require/js/models/todoModel.js | 2 +- .../stapes_require/js/stores/todoStore.js | 2 +- .../stapes_require/js/views/todoView.js | 2 +- .../stapes_require/readme.md | 18 + .../thorax_lumbar/README.md | 9 - .../thorax_lumbar/bower.json | 10 + .../bower_components/backbone/backbone.js} | 988 +- .../handlebars.js/handlebars.js | 2239 ++ .../bower_components/jquery/jquery.js | 8755 +++++++ .../lumbar-loader}/lumbar-loader-backbone.js | 5 +- .../lumbar-loader}/lumbar-loader-events.js | 3 +- .../lumbar-loader-localstorage.js | 6 +- .../lumbar-loader}/lumbar-loader-standard.js | 1 + .../lumbar-loader}/lumbar-loader.js | 3 +- .../script.js/dist}/script.js | 44 +- .../bower_components/thorax/thorax.js | 2670 ++ .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../bower_components/underscore/underscore.js | 1226 + .../thorax_lumbar/lumbar.json | 154 +- .../thorax_lumbar/public/base.js | 20482 ++++++++-------- .../thorax_lumbar/public/index.html | 23 +- .../thorax_lumbar/public/todomvc.js | 10 +- .../thorax_lumbar/readme.md | 35 + .../thorax_lumbar/src/js/lib/thorax.js | 16884 ------------- .../bower_components/todomvc-common/base.js | 38 - labs/dependency-examples/troopjs/index.html | 47 - labs/dependency-examples/troopjs/js/app.js | 29 - labs/dependency-examples/troopjs/js/config.js | 4 - .../troopjs/js/lib/troopjs-bundle.js | 3436 --- .../troopjs/js/widget/application.js | 30 - .../troopjs/js/widget/clear.js | 23 - .../troopjs/js/widget/count.js | 19 - .../troopjs/js/widget/create.js | 25 - .../troopjs/js/widget/display.js | 19 - .../troopjs/js/widget/escape.js | 73 - .../troopjs/js/widget/filters.js | 23 - .../troopjs/js/widget/item.html | 14 - .../troopjs/js/widget/list.js | 267 - .../troopjs/js/widget/mark.js | 35 - .../troopjs_require/bower.json | 11 + .../bower_components/jquery/jquery.js | 8837 +++++++ .../bower_components/requirejs/require.js | 2045 ++ .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes .../bower_components/troopjs-bundle/maxi.js | 6240 +++++ .../{troopjs => troopjs_require}/css/app.css | 4 + .../troopjs_require/index.html | 78 + .../troopjs_require/js/widget/clear.js | 23 + .../troopjs_require/js/widget/count.js | 19 + .../troopjs_require/js/widget/create.js | 25 + .../troopjs_require/js/widget/display.js | 17 + .../troopjs_require/js/widget/filters.js | 20 + .../troopjs_require/js/widget/item.html | 22 + .../troopjs_require/js/widget/list.js | 225 + .../troopjs_require/js/widget/mark.js | 46 + .../troopjs_require/readme.md | 16 + learn.json | 1975 ++ learn.template.json | 59 + readme.md | 35 +- site/js/main.js | 9 - tasks/Gruntfile.js | 42 + tasks/package.json | 10 + template/{component.json => bower.json} | 0 .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes template/components/todomvc-common/base.js | 38 - template/index.html | 6 +- template/readme.md | 44 +- template/readme_template.md | 2 +- vanilla-examples/vanillajs/bower.json | 8 + .../director/build/director.js | 712 + .../bower_components/todomvc-common/base.css | 555 + .../bower_components/todomvc-common/base.js | 209 + .../bower_components/todomvc-common/bg.png | Bin 0 -> 2126 bytes vanilla-examples/vanillajs/index.html | 82 +- vanilla-examples/vanillajs/js/app.js | 346 +- vanilla-examples/vanillajs/js/controller.js | 342 + vanilla-examples/vanillajs/js/helpers.js | 19 + vanilla-examples/vanillajs/js/model.js | 119 + vanilla-examples/vanillajs/js/store.js | 142 + vanilla-examples/vanillajs/js/view.js | 91 + vanilla-examples/vanillajs/readme.md | 5 + 1116 files changed, 350860 insertions(+), 117334 deletions(-) create mode 100644 architecture-examples/agilityjs/readme.md create mode 100644 architecture-examples/angularjs-perf/readme.md create mode 100644 architecture-examples/angularjs/js/directives/todoEscape.js create mode 100644 architecture-examples/angularjs/readme.md rename architecture-examples/backbone/js/views/{app.js => app-view.js} (81%) rename architecture-examples/backbone/js/views/{todos.js => todo-view.js} (93%) create mode 100644 architecture-examples/backbone/readme.md create mode 100644 architecture-examples/dart/.bowerrc create mode 100644 architecture-examples/dart/bower.json delete mode 100644 architecture-examples/dart/web/assets/base.js delete mode 100644 architecture-examples/dart/web/assets/ie.js rename {template/components => architecture-examples/dart/web/bower_components}/todomvc-common/base.css (80%) create mode 100644 architecture-examples/dart/web/bower_components/todomvc-common/base.js rename architecture-examples/dart/web/{assets => bower_components/todomvc-common}/bg.png (100%) create mode 100644 architecture-examples/dojo/bower.json rename {labs/dependency-examples/troopjs => architecture-examples/dojo}/bower_components/todomvc-common/base.css (80%) create mode 100644 architecture-examples/dojo/bower_components/todomvc-common/base.js rename {labs/architecture-examples/duel/src/main/webapp/css => architecture-examples/dojo/bower_components/todomvc-common}/bg.png (100%) create mode 100644 architecture-examples/emberjs/readme.md create mode 100644 architecture-examples/gwt/bower.json rename architecture-examples/{dart/web/assets => gwt/bower_components/todomvc-common}/base.css (76%) create mode 100644 architecture-examples/gwt/bower_components/todomvc-common/base.js rename {labs/architecture-examples/meteor/client/images => architecture-examples/gwt/bower_components/todomvc-common}/bg.png (100%) create mode 100644 architecture-examples/jquery/readme.md create mode 100644 architecture-examples/knockback/bower.json create mode 100644 architecture-examples/knockback/bower_components/Backbone.localStorage/backbone.localStorage.js create mode 100644 architecture-examples/knockback/bower_components/jquery/jquery.js rename {labs/architecture-examples/meteor/client/css => architecture-examples/knockback/bower_components/todomvc-common}/base.css (76%) create mode 100644 architecture-examples/knockback/bower_components/todomvc-common/base.js rename {labs/dependency-examples/troopjs => architecture-examples/knockback}/bower_components/todomvc-common/bg.png (100%) rename architecture-examples/maria/{lib/aristocrat => bower_components/aristocrat-bower}/aristocrat.js (98%) rename architecture-examples/maria/{lib/maria => bower_components/maria-bower}/maria.js (94%) create mode 100644 architecture-examples/maria/readme.md create mode 100644 architecture-examples/polymer/AUTHORS create mode 100644 architecture-examples/polymer/CONTRIBUTING.md create mode 100644 architecture-examples/polymer/LICENSE create mode 100644 architecture-examples/polymer/PATENTS create mode 100644 architecture-examples/polymer/README.md create mode 100644 architecture-examples/polymer/app/app.css rename {labs/dependency-examples/troopjs => architecture-examples/polymer}/bower.json (50%) create mode 100644 architecture-examples/polymer/bower_components/director/build/director.js create mode 100644 architecture-examples/polymer/bower_components/director/build/director.min.js create mode 100644 architecture-examples/polymer/bower_components/director/build/ender.js create mode 100644 architecture-examples/polymer/bower_components/polymer/polymer.min.js create mode 100644 architecture-examples/polymer/bower_components/todomvc-common/base.css create mode 100644 architecture-examples/polymer/bower_components/todomvc-common/base.js rename {template/components => architecture-examples/polymer/bower_components}/todomvc-common/bg.png (100%) create mode 100644 architecture-examples/polymer/elements/td-input.html create mode 100644 architecture-examples/polymer/elements/td-item.css create mode 100644 architecture-examples/polymer/elements/td-item.html create mode 100644 architecture-examples/polymer/elements/td-model.html rename labs/architecture-examples/ariatemplates/css/app.css => architecture-examples/polymer/elements/td-todos.css (70%) create mode 100644 architecture-examples/polymer/elements/td-todos.html create mode 100644 architecture-examples/polymer/index.html create mode 100644 architecture-examples/polymer/lib-elements/flatiron-director.html create mode 100644 architecture-examples/polymer/lib-elements/polymer-localstorage.html create mode 100644 architecture-examples/polymer/lib-elements/polymer-selection.html create mode 100644 architecture-examples/polymer/lib-elements/polymer-selector.html create mode 100644 architecture-examples/yui/bower.json create mode 100644 architecture-examples/yui/bower_components/todomvc-common/base.css create mode 100644 architecture-examples/yui/bower_components/todomvc-common/base.js create mode 100644 architecture-examples/yui/bower_components/todomvc-common/bg.png create mode 100644 architecture-examples/yui/readme.md create mode 100644 dependency-examples/backbone_require/readme.md delete mode 100644 dependency-examples/emberjs_require/css/app.css delete mode 100644 dependency-examples/emberjs_require/js/app.js delete mode 100644 dependency-examples/emberjs_require/js/app/controllers/entries.js delete mode 100644 dependency-examples/emberjs_require/js/app/controllers/todos.js delete mode 100644 dependency-examples/emberjs_require/js/app/models/store.js delete mode 100644 dependency-examples/emberjs_require/js/app/models/todo.js delete mode 100644 dependency-examples/emberjs_require/js/app/router.js delete mode 100644 dependency-examples/emberjs_require/js/app/specs/controllers/todos.js delete mode 100644 dependency-examples/emberjs_require/js/app/specs/helper.js delete mode 100644 dependency-examples/emberjs_require/js/app/specs/models/store.js delete mode 100644 dependency-examples/emberjs_require/js/app/specs/todoMVC.js delete mode 100644 dependency-examples/emberjs_require/js/app/specs/views/basic_acceptance.js delete mode 100644 dependency-examples/emberjs_require/js/app/templates/clear_button.html delete mode 100644 dependency-examples/emberjs_require/js/app/templates/filters.html delete mode 100644 dependency-examples/emberjs_require/js/app/templates/items.html delete mode 100644 dependency-examples/emberjs_require/js/app/templates/stats.html delete mode 100644 dependency-examples/emberjs_require/js/app/views/application.js delete mode 100644 dependency-examples/emberjs_require/js/app/views/clear_button.js delete mode 100644 dependency-examples/emberjs_require/js/app/views/filters.js delete mode 100644 dependency-examples/emberjs_require/js/app/views/items.js delete mode 100644 dependency-examples/emberjs_require/js/app/views/stats.js delete mode 100644 dependency-examples/emberjs_require/js/lib/ember-latest.min.js delete mode 100644 dependency-examples/emberjs_require/js/lib/require/require.js delete mode 100644 dependency-examples/emberjs_require/js/lib/require/text.js create mode 100644 dependency-examples/flight/readme.md create mode 100644 labs/architecture-examples/ariatemplates/bower.json create mode 100644 labs/architecture-examples/ariatemplates/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/ariatemplates/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/ariatemplates/bower_components/todomvc-common/bg.png create mode 100644 labs/architecture-examples/ariatemplates/readme.md create mode 100644 labs/architecture-examples/backbone.xmpp/bower.json rename labs/architecture-examples/backbone.xmpp/{js/lib => bower_components/Strophe.js}/strophe.js (84%) create mode 100644 labs/architecture-examples/backbone.xmpp/bower_components/backbone/backbone.js create mode 100644 labs/architecture-examples/backbone.xmpp/bower_components/jquery/jquery.js create mode 100644 labs/architecture-examples/backbone.xmpp/bower_components/lodash/lodash.js create mode 100644 labs/architecture-examples/backbone.xmpp/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/backbone.xmpp/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/backbone.xmpp/bower_components/todomvc-common/bg.png rename labs/architecture-examples/backbone.xmpp/{README.md => readme.md} (100%) delete mode 100644 labs/architecture-examples/backbone_marionette/.jshintignore delete mode 100644 labs/architecture-examples/backbone_marionette/README.md create mode 100644 labs/architecture-examples/backbone_marionette/readme.md delete mode 100644 labs/architecture-examples/cujo/README.md create mode 100644 labs/architecture-examples/cujo/bower.json create mode 100644 labs/architecture-examples/cujo/bower_components/cola/Collection.js create mode 100644 labs/architecture-examples/cujo/bower_components/cola/Model.js rename labs/architecture-examples/cujo/{lib => bower_components}/cola/SortedMap.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/adapter/Array.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/adapter/LocalStorage.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/adapter/Object.js (81%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/adapter/ObjectToArray.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/adapter/Query.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/adapter/makeJoined.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/adapter/makeTransformed.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/adapter/makeTransformedProperties.js (100%) create mode 100644 labs/architecture-examples/cujo/bower_components/cola/adapterResolver.js rename labs/architecture-examples/cujo/{lib => bower_components}/cola/cola.js (83%) create mode 100644 labs/architecture-examples/cujo/bower_components/cola/collectionAdapterResolver.js rename labs/architecture-examples/cujo/{lib => bower_components}/cola/comparator/byProperty.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/comparator/compose.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/comparator/naturalOrder.js (98%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/comparator/reverse.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/dom/adapter/Node.js (66%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/dom/adapter/NodeList.js (92%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/dom/bindingHandler.js (87%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/dom/classList.js (79%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/dom/events.js (99%) create mode 100644 labs/architecture-examples/cujo/bower_components/cola/dom/form.js rename labs/architecture-examples/cujo/{lib => bower_components}/cola/dom/formElementFinder.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/dom/guess.js (97%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/dom/has.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/enqueue.js (100%) create mode 100644 labs/architecture-examples/cujo/bower_components/cola/hub/Base.js create mode 100644 labs/architecture-examples/cujo/bower_components/cola/hub/eventProcessor.js rename labs/architecture-examples/cujo/{lib => bower_components}/cola/identifier/default.js (98%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/identifier/property.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/network/strategy/base.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/network/strategy/changeEvent.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/network/strategy/collectThenDeliver.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/network/strategy/compose.js (87%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/network/strategy/default.js (99%) create mode 100644 labs/architecture-examples/cujo/bower_components/cola/network/strategy/defaultModel.js rename labs/architecture-examples/cujo/{lib => bower_components}/cola/network/strategy/minimal.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/network/strategy/syncAfterJoin.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/network/strategy/syncDataDirectly.js (99%) create mode 100644 labs/architecture-examples/cujo/bower_components/cola/network/strategy/syncModel.js rename labs/architecture-examples/cujo/{lib => bower_components}/cola/network/strategy/targetFirstItem.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/network/strategy/validate.js (99%) create mode 100644 labs/architecture-examples/cujo/bower_components/cola/objectAdapterResolver.js rename labs/architecture-examples/cujo/{lib => bower_components}/cola/projection/assign.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/projection/inherit.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/relational/hashJoin.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/relational/propertiesKey.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/relational/strategy/leftOuterJoin.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/transform/compose.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/transform/configure.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/transform/createEnum.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/transform/expression.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/validation/composeValidators.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/cola/validation/form/formValidationHandler.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/curl/src/curl.js (58%) rename labs/architecture-examples/cujo/{lib => bower_components}/curl/src/curl/debug.js (79%) rename labs/architecture-examples/cujo/{lib => bower_components}/curl/src/curl/domReady.js (98%) create mode 100644 labs/architecture-examples/cujo/bower_components/curl/src/curl/loader/cjsm11.js rename labs/architecture-examples/cujo/{lib => bower_components}/curl/src/curl/plugin/README.md (100%) create mode 100644 labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/_fetchText.js rename labs/architecture-examples/cujo/{lib => bower_components}/curl/src/curl/plugin/async.js (72%) create mode 100644 labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/css.js rename labs/architecture-examples/cujo/{lib => bower_components}/curl/src/curl/plugin/domReady.js (78%) create mode 100644 labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/i18n.js rename labs/architecture-examples/cujo/{lib => bower_components}/curl/src/curl/plugin/js.js (79%) create mode 100644 labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/json.js rename labs/architecture-examples/cujo/{lib => bower_components}/curl/src/curl/plugin/link.js (93%) create mode 100644 labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/style.js create mode 100644 labs/architecture-examples/cujo/bower_components/curl/src/curl/plugin/text.js rename labs/architecture-examples/cujo/{lib => bower_components}/curl/src/curl/shim/dojo16.js (96%) rename labs/architecture-examples/cujo/{lib => bower_components}/curl/src/curl/shim/ssjs.js (92%) rename labs/architecture-examples/cujo/{lib => bower_components}/curl/src/curl/tdd/runner.js (98%) rename labs/architecture-examples/cujo/{lib => bower_components}/curl/src/curl/tdd/undefine.js (95%) create mode 100644 labs/architecture-examples/cujo/bower_components/meld/aspect/cache.js create mode 100644 labs/architecture-examples/cujo/bower_components/meld/aspect/memoize.js create mode 100644 labs/architecture-examples/cujo/bower_components/meld/aspect/trace.js create mode 100644 labs/architecture-examples/cujo/bower_components/meld/meld.js create mode 100644 labs/architecture-examples/cujo/bower_components/poly/all.js rename labs/architecture-examples/cujo/{lib => bower_components}/poly/array.js (99%) create mode 100644 labs/architecture-examples/cujo/bower_components/poly/date.js create mode 100644 labs/architecture-examples/cujo/bower_components/poly/es5-strict.js create mode 100644 labs/architecture-examples/cujo/bower_components/poly/es5.js rename labs/architecture-examples/cujo/{lib => bower_components}/poly/function.js (95%) create mode 100644 labs/architecture-examples/cujo/bower_components/poly/json.js rename labs/architecture-examples/cujo/{lib => bower_components}/poly/lib/_base.js (81%) rename labs/architecture-examples/cujo/{lib => bower_components}/poly/object.js (63%) rename labs/architecture-examples/cujo/{lib => bower_components}/poly/poly.js (58%) create mode 100644 labs/architecture-examples/cujo/bower_components/poly/setImmediate.js create mode 100644 labs/architecture-examples/cujo/bower_components/poly/strict.js rename labs/architecture-examples/cujo/{lib => bower_components}/poly/string.js (57%) create mode 100644 labs/architecture-examples/cujo/bower_components/poly/support/json3.js create mode 100644 labs/architecture-examples/cujo/bower_components/poly/xhr.js create mode 100644 labs/architecture-examples/cujo/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/cujo/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/cujo/bower_components/todomvc-common/bg.png rename labs/architecture-examples/cujo/{lib => bower_components}/when/apply.js (80%) create mode 100644 labs/architecture-examples/cujo/bower_components/when/callbacks.js rename labs/architecture-examples/cujo/{lib => bower_components}/when/cancelable.js (67%) create mode 100644 labs/architecture-examples/cujo/bower_components/when/debug.js create mode 100644 labs/architecture-examples/cujo/bower_components/when/delay.js create mode 100644 labs/architecture-examples/cujo/bower_components/when/function.js create mode 100644 labs/architecture-examples/cujo/bower_components/when/guard.js create mode 100644 labs/architecture-examples/cujo/bower_components/when/keys.js create mode 100644 labs/architecture-examples/cujo/bower_components/when/node/function.js create mode 100644 labs/architecture-examples/cujo/bower_components/when/parallel.js create mode 100644 labs/architecture-examples/cujo/bower_components/when/pipeline.js create mode 100644 labs/architecture-examples/cujo/bower_components/when/poll.js create mode 100644 labs/architecture-examples/cujo/bower_components/when/sequence.js rename labs/architecture-examples/cujo/{lib => bower_components}/when/timed.js (53%) create mode 100644 labs/architecture-examples/cujo/bower_components/when/timeout.js create mode 100644 labs/architecture-examples/cujo/bower_components/when/unfold.js create mode 100644 labs/architecture-examples/cujo/bower_components/when/unfold/list.js create mode 100644 labs/architecture-examples/cujo/bower_components/when/when.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/aop.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/builder/cram.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/connect.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/debug.js rename labs/architecture-examples/cujo/{lib => bower_components}/wire/dojo/data.js (75%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/dojo/dijit.js (73%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/dojo/dom.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/dojo/events.js (86%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/dojo/on.js (89%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/dojo/pubsub.js (84%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/dojo/store.js (94%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/dom.js (86%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/dom/render.js (80%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/dom/transform/cardinality.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/dom/transform/mapClasses.js (82%) create mode 100644 labs/architecture-examples/cujo/bower_components/wire/dom/transform/mapTokenList.js rename labs/architecture-examples/cujo/{lib => bower_components}/wire/dom/transform/replaceClasses.js (93%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/dom/transform/toggleClasses.js (98%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/domReady.js (80%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/jquery/dom.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/jquery/on.js (97%) create mode 100644 labs/architecture-examples/cujo/bower_components/wire/jquery/ui.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/ComponentFactory.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/Container.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/WireContext.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/WireProxy.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/advice.js rename labs/architecture-examples/cujo/{lib => bower_components}/wire/lib/array.js (56%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/lib/connection.js (85%) create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/context.js rename labs/architecture-examples/cujo/{lib => bower_components}/wire/lib/dom/base.js (75%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/lib/functional.js (61%) create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/graph/DirectedGraph.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/graph/formatCycles.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/graph/tarjan.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/graph/trackInflightRefs.js rename labs/architecture-examples/cujo/{lib/wire/lib/component.js => bower_components/wire/lib/instantiate.js} (80%) create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/invoker.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/lifecycle.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/loader.js rename labs/architecture-examples/cujo/{lib => bower_components}/wire/lib/object.js (52%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/lib/plugin-base/dom.js (66%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/lib/plugin-base/on.js (55%) create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/plugin/basePlugin.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/plugin/defaultPlugins.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/plugin/priority.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/plugin/registry.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/plugin/wirePlugin.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/resolver.js create mode 100644 labs/architecture-examples/cujo/bower_components/wire/lib/scope.js rename labs/architecture-examples/cujo/{lib => bower_components}/wire/on.js (99%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/sizzle.js (100%) rename labs/architecture-examples/cujo/{lib => bower_components}/wire/wire.js (66%) delete mode 100644 labs/architecture-examples/cujo/lib/aop/LICENSE.txt delete mode 100644 labs/architecture-examples/cujo/lib/aop/README.md delete mode 100644 labs/architecture-examples/cujo/lib/aop/aop.js delete mode 100644 labs/architecture-examples/cujo/lib/aop/package.json delete mode 100644 labs/architecture-examples/cujo/lib/cola/AdapterResolver.js delete mode 100644 labs/architecture-examples/cujo/lib/cola/Hub.js delete mode 100644 labs/architecture-examples/cujo/lib/cola/demo/ArrayToNodeList.html delete mode 100644 labs/architecture-examples/cujo/lib/cola/doc/ICollectionAdapter.js delete mode 100644 labs/architecture-examples/cujo/lib/cola/doc/IObjectAdapter.js delete mode 100644 labs/architecture-examples/cujo/lib/cola/dom/formToObject.js delete mode 100644 labs/architecture-examples/cujo/lib/cola/package.json delete mode 100644 labs/architecture-examples/cujo/lib/curl/.gitmodules delete mode 100644 labs/architecture-examples/cujo/lib/curl/LICENSE.txt delete mode 100644 labs/architecture-examples/cujo/lib/curl/README.md delete mode 100644 labs/architecture-examples/cujo/lib/curl/package.json delete mode 100644 labs/architecture-examples/cujo/lib/curl/src/curl/loader/cjsm11.js delete mode 100644 labs/architecture-examples/cujo/lib/curl/src/curl/plugin/builder/css.js delete mode 100644 labs/architecture-examples/cujo/lib/curl/src/curl/plugin/builder/text.js delete mode 100644 labs/architecture-examples/cujo/lib/curl/src/curl/plugin/css.js delete mode 100644 labs/architecture-examples/cujo/lib/curl/src/curl/plugin/i18n.js delete mode 100644 labs/architecture-examples/cujo/lib/curl/src/curl/plugin/text.js delete mode 100644 labs/architecture-examples/cujo/lib/poly/LICENSE.txt delete mode 100644 labs/architecture-examples/cujo/lib/poly/README.md delete mode 100644 labs/architecture-examples/cujo/lib/poly/all.js delete mode 100644 labs/architecture-examples/cujo/lib/poly/json.js delete mode 100644 labs/architecture-examples/cujo/lib/poly/lib/_async.js delete mode 100644 labs/architecture-examples/cujo/lib/poly/lib/_json.js delete mode 100644 labs/architecture-examples/cujo/lib/poly/package.json delete mode 100644 labs/architecture-examples/cujo/lib/poly/support/json2.js delete mode 100644 labs/architecture-examples/cujo/lib/poly/xhr.js delete mode 100644 labs/architecture-examples/cujo/lib/when/.travis.yml delete mode 100644 labs/architecture-examples/cujo/lib/when/LICENSE.txt delete mode 100644 labs/architecture-examples/cujo/lib/when/README.md delete mode 100644 labs/architecture-examples/cujo/lib/when/debug.js delete mode 100644 labs/architecture-examples/cujo/lib/when/delay.js delete mode 100644 labs/architecture-examples/cujo/lib/when/package.json delete mode 100644 labs/architecture-examples/cujo/lib/when/timeout.js delete mode 100644 labs/architecture-examples/cujo/lib/when/when.js delete mode 100644 labs/architecture-examples/cujo/lib/wire/LICENSE.txt delete mode 100644 labs/architecture-examples/cujo/lib/wire/README.md delete mode 100644 labs/architecture-examples/cujo/lib/wire/aop.js delete mode 100644 labs/architecture-examples/cujo/lib/wire/base.js delete mode 100644 labs/architecture-examples/cujo/lib/wire/connect.js delete mode 100644 labs/architecture-examples/cujo/lib/wire/cram/builder.js delete mode 100644 labs/architecture-examples/cujo/lib/wire/debug.js delete mode 100644 labs/architecture-examples/cujo/lib/wire/dom/transform/mapTokenList.js delete mode 100644 labs/architecture-examples/cujo/lib/wire/lib/context.js delete mode 100644 labs/architecture-examples/cujo/lib/wire/lib/lifecycle.js delete mode 100644 labs/architecture-examples/cujo/lib/wire/lib/moduleLoader.js delete mode 100644 labs/architecture-examples/cujo/lib/wire/lib/resolver.js delete mode 100644 labs/architecture-examples/cujo/lib/wire/package.json create mode 100644 labs/architecture-examples/cujo/readme.md delete mode 100644 labs/architecture-examples/derby/README.md create mode 100644 labs/architecture-examples/derby/readme.md delete mode 100644 labs/architecture-examples/dermis/README.md create mode 100644 labs/architecture-examples/dermis/bower.json create mode 100644 labs/architecture-examples/dermis/bower_components/jquery/jquery.js create mode 100644 labs/architecture-examples/dermis/bower_components/requirejs/require.js create mode 100644 labs/architecture-examples/dermis/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/dermis/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/dermis/bower_components/todomvc-common/bg.png create mode 100644 labs/architecture-examples/dermis/readme.md create mode 100644 labs/architecture-examples/dijon/bower.json create mode 100644 labs/architecture-examples/dijon/bower_components/handlebars.js/handlebars.js create mode 100644 labs/architecture-examples/dijon/bower_components/jquery/jquery.js create mode 100644 labs/architecture-examples/dijon/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/dijon/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/dijon/bower_components/todomvc-common/bg.png create mode 100644 labs/architecture-examples/duel/.bowerrc create mode 100644 labs/architecture-examples/duel/bower.json create mode 100644 labs/architecture-examples/duel/src/main/webapp/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/duel/src/main/webapp/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/duel/src/main/webapp/bower_components/todomvc-common/bg.png delete mode 100644 labs/architecture-examples/duel/src/main/webapp/css/base.css rename labs/architecture-examples/duel/www/cdn/{1de7392f10ea2465d68b839144090d158ba7730f.js => 4340176df828f72a94b201a48c223860b95908dc.js} (52%) delete mode 100644 labs/architecture-examples/duel/www/cdn/502117dcda6b1a71004e818c348c9de5fc80966a.css create mode 100644 labs/architecture-examples/duel/www/cdn/d764469b1882372019d07f8c1174b1d64507e56d.css create mode 100644 labs/architecture-examples/epitome/bower.json create mode 100644 labs/architecture-examples/epitome/bower_components/Epitome/Epitome-min.js create mode 100644 labs/architecture-examples/epitome/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/epitome/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/epitome/bower_components/todomvc-common/bg.png delete mode 100644 labs/architecture-examples/epitome/js/lib/Epitome-min.js create mode 100644 labs/architecture-examples/extjs/bower.json create mode 100644 labs/architecture-examples/extjs/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/extjs/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/extjs/bower_components/todomvc-common/bg.png create mode 100644 labs/architecture-examples/extjs/readme.md create mode 100644 labs/architecture-examples/extjs_deftjs/bower.json create mode 100644 labs/architecture-examples/extjs_deftjs/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/extjs_deftjs/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/extjs_deftjs/bower_components/todomvc-common/bg.png rename labs/architecture-examples/extjs_deftjs/{README.md => readme.md} (62%) create mode 100644 labs/architecture-examples/firebase-angular/bower.json create mode 100644 labs/architecture-examples/firebase-angular/bower_components/angular-fire/angularFire.js create mode 100644 labs/architecture-examples/firebase-angular/bower_components/angular-fire/bower.json create mode 100644 labs/architecture-examples/firebase-angular/bower_components/angular-mocks/angular-mocks.js create mode 100644 labs/architecture-examples/firebase-angular/bower_components/angular-mocks/bower.json create mode 100644 labs/architecture-examples/firebase-angular/bower_components/angular/angular.js create mode 100644 labs/architecture-examples/firebase-angular/bower_components/angular/angular.min.js create mode 100644 labs/architecture-examples/firebase-angular/bower_components/angular/bower.json create mode 100644 labs/architecture-examples/firebase-angular/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/firebase-angular/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/firebase-angular/bower_components/todomvc-common/bg.png create mode 100644 labs/architecture-examples/firebase-angular/index.html create mode 100644 labs/architecture-examples/firebase-angular/js/app.js create mode 100644 labs/architecture-examples/firebase-angular/js/controllers/todoCtrl.js create mode 100644 labs/architecture-examples/firebase-angular/js/directives/todoBlur.js create mode 100644 labs/architecture-examples/firebase-angular/js/directives/todoEscape.js create mode 100644 labs/architecture-examples/firebase-angular/js/directives/todoFocus.js create mode 100644 labs/architecture-examples/firebase-angular/readme.md create mode 100644 labs/architecture-examples/kendo/bower.json create mode 100644 labs/architecture-examples/kendo/bower_components/jquery/jquery.js create mode 100644 labs/architecture-examples/kendo/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/kendo/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/kendo/bower_components/todomvc-common/bg.png create mode 100644 labs/architecture-examples/kendo/readme.md create mode 100644 labs/architecture-examples/knockoutjs_classBindingProvider/bower.json create mode 100644 labs/architecture-examples/knockoutjs_classBindingProvider/bower_components/director/build/director.js create mode 100644 labs/architecture-examples/knockoutjs_classBindingProvider/bower_components/knockout.js/knockout.js create mode 100644 labs/architecture-examples/knockoutjs_classBindingProvider/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/knockoutjs_classBindingProvider/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/knockoutjs_classBindingProvider/bower_components/todomvc-common/bg.png delete mode 100644 labs/architecture-examples/knockoutjs_classBindingProvider/js/lib/knockout.min.js create mode 100644 labs/architecture-examples/meteor/.bowerrc create mode 100644 labs/architecture-examples/meteor/.meteor/release create mode 100644 labs/architecture-examples/meteor/bower.json create mode 100644 labs/architecture-examples/meteor/client/bower_components/director/build/director.js create mode 100644 labs/architecture-examples/meteor/client/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/meteor/client/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/meteor/client/bower_components/todomvc-common/bg.png delete mode 100644 labs/architecture-examples/meteor/client/lib/base.js delete mode 100644 labs/architecture-examples/meteor/client/lib/director-1.1.3.min.js delete mode 100644 labs/architecture-examples/meteor/client/lib/ie.js create mode 100644 labs/architecture-examples/montage/bower.json create mode 100644 labs/architecture-examples/montage/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/montage/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/montage/bower_components/todomvc-common/bg.png delete mode 100644 labs/architecture-examples/o_O/index.html delete mode 100644 labs/architecture-examples/o_O/js/app.js delete mode 100644 labs/architecture-examples/o_O/js/lib/o_O.js delete mode 100644 labs/architecture-examples/o_O/js/lib/o_O.router.js create mode 100644 labs/architecture-examples/plastronjs/bower.json create mode 100644 labs/architecture-examples/plastronjs/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/plastronjs/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/plastronjs/bower_components/todomvc-common/bg.png create mode 100644 labs/architecture-examples/polymer/index.html delete mode 100644 labs/architecture-examples/puremvc/README.md create mode 100644 labs/architecture-examples/puremvc/readme.md create mode 100644 labs/architecture-examples/rappidjs/bower.json create mode 100644 labs/architecture-examples/rappidjs/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/rappidjs/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/rappidjs/bower_components/todomvc-common/bg.png create mode 100644 labs/architecture-examples/rappidjs/readme.md create mode 100644 labs/architecture-examples/react/bower.json create mode 100644 labs/architecture-examples/react/bower_components/director/.bower.json create mode 100644 labs/architecture-examples/react/bower_components/director/.gitignore create mode 100644 labs/architecture-examples/react/bower_components/director/.travis.yml create mode 100644 labs/architecture-examples/react/bower_components/director/LICENSE create mode 100644 labs/architecture-examples/react/bower_components/director/README.md create mode 100755 labs/architecture-examples/react/bower_components/director/bin/build create mode 100644 labs/architecture-examples/react/bower_components/director/build/director.js create mode 100644 labs/architecture-examples/react/bower_components/director/build/director.min.js create mode 100644 labs/architecture-examples/react/bower_components/director/build/ender.js create mode 100644 labs/architecture-examples/react/bower_components/director/examples/http.js create mode 100644 labs/architecture-examples/react/bower_components/director/img/director.png create mode 100644 labs/architecture-examples/react/bower_components/director/img/hashRoute.png create mode 100644 labs/architecture-examples/react/bower_components/director/lib/director.js create mode 100644 labs/architecture-examples/react/bower_components/director/lib/director/browser.js create mode 100644 labs/architecture-examples/react/bower_components/director/lib/director/cli.js create mode 100644 labs/architecture-examples/react/bower_components/director/lib/director/http/index.js create mode 100644 labs/architecture-examples/react/bower_components/director/lib/director/http/methods.js create mode 100644 labs/architecture-examples/react/bower_components/director/lib/director/http/responses.js create mode 100644 labs/architecture-examples/react/bower_components/director/lib/director/router.js create mode 100644 labs/architecture-examples/react/bower_components/director/package.json create mode 100644 labs/architecture-examples/react/bower_components/director/test/browser/backend/backend.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/browser/browserify-harness.html create mode 100644 labs/architecture-examples/react/bower_components/director/test/browser/helpers/api.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/browser/html5-routes-harness.html create mode 100644 labs/architecture-examples/react/bower_components/director/test/browser/html5-routes-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/browser/routes-harness.html create mode 100644 labs/architecture-examples/react/bower_components/director/test/browser/routes-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/cli/dispatch-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/cli/mount-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/cli/path-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/core/dispatch-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/core/insert-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/core/mount-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/core/on-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/core/path-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/core/regifystring-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/helpers/index.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/helpers/macros.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/http/accept-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/http/attach-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/http/before-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/http/http-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/http/methods-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/http/responses-test.js create mode 100644 labs/architecture-examples/react/bower_components/director/test/server/http/stream-test.js create mode 100644 labs/architecture-examples/react/bower_components/react/.bower.json create mode 100644 labs/architecture-examples/react/bower_components/react/JSXTransformer.js create mode 100644 labs/architecture-examples/react/bower_components/react/bower.json create mode 100644 labs/architecture-examples/react/bower_components/react/react.js create mode 100644 labs/architecture-examples/react/bower_components/react/react.min.js create mode 100644 labs/architecture-examples/react/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/react/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/react/bower_components/todomvc-common/bg.png create mode 100644 labs/architecture-examples/react/index.html create mode 100644 labs/architecture-examples/react/js/app.jsx create mode 100644 labs/architecture-examples/react/js/footer.jsx create mode 100644 labs/architecture-examples/react/js/todoItem.jsx create mode 100644 labs/architecture-examples/react/js/utils.jsx create mode 100644 labs/architecture-examples/react/readme.md create mode 100644 labs/architecture-examples/sapui5/bower.json create mode 100644 labs/architecture-examples/sapui5/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/sapui5/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/sapui5/bower_components/todomvc-common/bg.png create mode 100644 labs/architecture-examples/sapui5/css/base.css create mode 100644 labs/architecture-examples/sapui5/img/bg.png create mode 100644 labs/architecture-examples/sapui5/index.html create mode 100644 labs/architecture-examples/sapui5/js/app.js create mode 100644 labs/architecture-examples/sapui5/js/todo/SmartTextField.js create mode 100644 labs/architecture-examples/sapui5/js/todo/Todo.controller.js create mode 100644 labs/architecture-examples/sapui5/js/todo/Todo.view.js create mode 100644 labs/architecture-examples/sapui5/js/todo/TodoPersistency.js create mode 100644 labs/architecture-examples/sapui5/js/todo/formatters.js delete mode 100644 labs/architecture-examples/socketstream/README.md create mode 100644 labs/architecture-examples/socketstream/readme.md create mode 100644 labs/architecture-examples/somajs/bower.json create mode 100644 labs/architecture-examples/somajs/bower_components/director/build/director.js create mode 100644 labs/architecture-examples/somajs/bower_components/soma-template/build/soma-template.js create mode 100644 labs/architecture-examples/somajs/bower_components/soma.js/build/soma.js create mode 100644 labs/architecture-examples/somajs/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/somajs/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/somajs/bower_components/todomvc-common/bg.png rename labs/architecture-examples/{rappidjs => somajs}/css/app.css (51%) delete mode 100644 labs/architecture-examples/somajs/js/lib/soma-native_v1.0.2_min.js create mode 100644 labs/architecture-examples/somajs/js/models/router.js create mode 100644 labs/architecture-examples/somajs/js/models/todos.js delete mode 100644 labs/architecture-examples/somajs/js/todos/controllers/controllers.js delete mode 100644 labs/architecture-examples/somajs/js/todos/models/models.js delete mode 100644 labs/architecture-examples/somajs/js/todos/views/views.js create mode 100644 labs/architecture-examples/somajs/js/views/footer.js create mode 100644 labs/architecture-examples/somajs/js/views/header.js create mode 100644 labs/architecture-examples/somajs/js/views/main.js create mode 100644 labs/architecture-examples/stapes/bower.json create mode 100644 labs/architecture-examples/stapes/bower_components/handlebars.js/handlebars.js create mode 100644 labs/architecture-examples/stapes/bower_components/jquery/jquery.js create mode 100644 labs/architecture-examples/stapes/bower_components/stapes/stapes.js create mode 100644 labs/architecture-examples/stapes/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/stapes/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/stapes/bower_components/todomvc-common/bg.png delete mode 100644 labs/architecture-examples/stapes/js/lib/stapes.js create mode 100644 labs/architecture-examples/stapes/readme.md create mode 100644 labs/architecture-examples/thorax/bower.json rename labs/architecture-examples/{typescript-backbone/js/libs => thorax/bower_components}/backbone/backbone.js (100%) create mode 100644 labs/architecture-examples/thorax/bower_components/handlebars.js/handlebars.js create mode 100644 labs/architecture-examples/thorax/bower_components/jquery/jquery.js create mode 100644 labs/architecture-examples/thorax/bower_components/thorax/thorax.js create mode 100644 labs/architecture-examples/thorax/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/thorax/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/thorax/bower_components/todomvc-common/bg.png rename labs/{dependency-examples/backbone_marionette_require/js/lib => architecture-examples/thorax/bower_components/underscore}/underscore.js (61%) delete mode 100644 labs/architecture-examples/thorax/js/lib/thorax.js rename labs/architecture-examples/thorax/{README.md => readme.md} (53%) delete mode 100644 labs/architecture-examples/typescript-angular/ReadMe.md create mode 100644 labs/architecture-examples/typescript-angular/bower.json create mode 100644 labs/architecture-examples/typescript-angular/bower_components/angular/angular.js create mode 100644 labs/architecture-examples/typescript-angular/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/typescript-angular/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/typescript-angular/bower_components/todomvc-common/bg.png create mode 100644 labs/architecture-examples/typescript-angular/readme.md create mode 100644 labs/architecture-examples/typescript-backbone/bower.json create mode 100644 labs/architecture-examples/typescript-backbone/bower_components/backbone/backbone.js create mode 100644 labs/architecture-examples/typescript-backbone/bower_components/jquery/jquery.js create mode 100644 labs/architecture-examples/typescript-backbone/bower_components/lodash/lodash.js create mode 100644 labs/architecture-examples/typescript-backbone/bower_components/todomvc-common/base.css create mode 100644 labs/architecture-examples/typescript-backbone/bower_components/todomvc-common/base.js create mode 100644 labs/architecture-examples/typescript-backbone/bower_components/todomvc-common/bg.png create mode 100644 labs/dependency-examples/angularjs_require/readme.md delete mode 100644 labs/dependency-examples/backbone_marionette_require/.jshintignore create mode 100644 labs/dependency-examples/backbone_marionette_require/bower.json create mode 100644 labs/dependency-examples/backbone_marionette_require/bower_components/backbone.localStorage/backbone.localStorage.js create mode 100644 labs/dependency-examples/backbone_marionette_require/bower_components/backbone.marionette/lib/backbone.marionette.js create mode 100644 labs/dependency-examples/backbone_marionette_require/bower_components/backbone/backbone.js rename labs/dependency-examples/{troopjs => backbone_marionette_require}/bower_components/jquery/jquery.js (68%) create mode 100644 labs/dependency-examples/backbone_marionette_require/bower_components/requirejs/require.js create mode 100644 labs/dependency-examples/backbone_marionette_require/bower_components/todomvc-common/base.css create mode 100644 labs/dependency-examples/backbone_marionette_require/bower_components/todomvc-common/base.js create mode 100644 labs/dependency-examples/backbone_marionette_require/bower_components/todomvc-common/bg.png create mode 100644 labs/dependency-examples/backbone_marionette_require/bower_components/underscore/underscore.js delete mode 100644 labs/dependency-examples/backbone_marionette_require/index-dev.html delete mode 100644 labs/dependency-examples/backbone_marionette_require/js/lib/backbone-localStorage.js delete mode 100644 labs/dependency-examples/backbone_marionette_require/js/lib/backbone.js delete mode 100644 labs/dependency-examples/backbone_marionette_require/js/lib/backbone.marionette.js delete mode 100644 labs/dependency-examples/backbone_marionette_require/js/lib/require.js delete mode 100644 labs/dependency-examples/backbone_marionette_require/js/main.built.js delete mode 100644 labs/dependency-examples/backbone_marionette_require/js/vent.js create mode 100644 labs/dependency-examples/backbone_marionette_require/js/views/CompletedCount.js delete mode 100644 labs/dependency-examples/backbone_marionette_require/r.js create mode 100644 labs/dependency-examples/backbone_marionette_require/readme.md create mode 100644 labs/dependency-examples/canjs_require/bower.json create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/construct.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/construct/proxy.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/construct/super.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/control.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/control/plugin.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/control/route.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/model.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/observe.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/observe/attributes.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/observe/backup.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/observe/compute.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/observe/delegate.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/observe/list.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/observe/setter.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/observe/validations.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/route.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/array/each.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/can.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/deferred.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/dojo.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/event.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/fixture.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/fragment.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/hashchange.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/jquery.js rename labs/dependency-examples/canjs_require/{js/lib => bower_components/CanJS/amd}/can/util/library.js (52%) create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/mootools.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/object.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/object/isplain.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/string.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/string/deparam.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/yui.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/util/zepto.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/view.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/view/ejs.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/view/modifiers.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/view/mustache.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/view/render.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/CanJS/amd/can/view/scanner.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/jquery/jquery.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/requirejs/require.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/todomvc-common/base.css create mode 100644 labs/dependency-examples/canjs_require/bower_components/todomvc-common/base.js create mode 100644 labs/dependency-examples/canjs_require/bower_components/todomvc-common/bg.png rename labs/dependency-examples/canjs_require/js/{app => controls}/todos.js (94%) delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/construct.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/construct/proxy.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/construct/super.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/control.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/control/plugin.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/control/route.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/model.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/observe.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/observe/attributes.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/observe/backup.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/observe/compute.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/observe/delegate.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/observe/list.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/observe/setter.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/observe/validations.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/route.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/array/each.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/can.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/deferred.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/dojo.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/event.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/fixture.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/fragment.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/jquery.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/mootools.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/object.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/object/extend.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/object/isplain.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/string.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/string/deparam.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/yui.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/util/zepto.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/view.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/view/ejs.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/view/modifiers.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/view/mustache.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/view/render.js delete mode 100644 labs/dependency-examples/canjs_require/js/lib/can/view/scanner.js rename labs/dependency-examples/canjs_require/js/{app => }/models/localstorage.js (78%) rename labs/dependency-examples/canjs_require/js/{app => }/models/todo.js (80%) delete mode 100644 labs/dependency-examples/chaplin-brunch/README.md delete mode 100644 labs/dependency-examples/chaplin-brunch/app/controllers/base/controller.coffee delete mode 100644 labs/dependency-examples/chaplin-brunch/app/controllers/footer-controller.coffee delete mode 100644 labs/dependency-examples/chaplin-brunch/app/controllers/header-controller.coffee delete mode 100644 labs/dependency-examples/chaplin-brunch/app/controllers/todos-controller.coffee delete mode 100644 labs/dependency-examples/chaplin-brunch/app/lib/support.coffee delete mode 100644 labs/dependency-examples/chaplin-brunch/app/lib/utils.coffee delete mode 100644 labs/dependency-examples/chaplin-brunch/app/lib/view-helper.coffee delete mode 100644 labs/dependency-examples/chaplin-brunch/app/models/base/collection.coffee delete mode 100644 labs/dependency-examples/chaplin-brunch/app/models/base/model.coffee delete mode 100644 labs/dependency-examples/chaplin-brunch/app/views/layout.coffee create mode 100644 labs/dependency-examples/chaplin-brunch/bower.json create mode 100644 labs/dependency-examples/chaplin-brunch/bower_components/todomvc-common/base.css create mode 100644 labs/dependency-examples/chaplin-brunch/bower_components/todomvc-common/base.js create mode 100644 labs/dependency-examples/chaplin-brunch/bower_components/todomvc-common/bg.png create mode 100644 labs/dependency-examples/chaplin-brunch/public/app.js create mode 100644 labs/dependency-examples/chaplin-brunch/public/app.js.map delete mode 100644 labs/dependency-examples/chaplin-brunch/public/javascripts/app.js delete mode 100644 labs/dependency-examples/chaplin-brunch/public/javascripts/vendor.js delete mode 100644 labs/dependency-examples/chaplin-brunch/public/stylesheets/app.css create mode 100644 labs/dependency-examples/chaplin-brunch/readme.md delete mode 100644 labs/dependency-examples/chaplin-brunch/vendor/scripts/backbone-localStorage.js delete mode 100644 labs/dependency-examples/chaplin-brunch/vendor/scripts/chaplin-0.5.0.coffee delete mode 100644 labs/dependency-examples/chaplin-brunch/vendor/scripts/console-helper.js create mode 100644 labs/dependency-examples/durandal/bower.json create mode 100644 labs/dependency-examples/durandal/bower_components/durandal/amd/require.js create mode 100644 labs/dependency-examples/durandal/bower_components/durandal/amd/text.js create mode 100644 labs/dependency-examples/durandal/bower_components/durandal/app.js create mode 100644 labs/dependency-examples/durandal/bower_components/durandal/composition.js create mode 100644 labs/dependency-examples/durandal/bower_components/durandal/events.js create mode 100644 labs/dependency-examples/durandal/bower_components/durandal/modalDialog.js create mode 100644 labs/dependency-examples/durandal/bower_components/durandal/plugins/router.js create mode 100644 labs/dependency-examples/durandal/bower_components/durandal/system.js create mode 100644 labs/dependency-examples/durandal/bower_components/durandal/viewEngine.js create mode 100644 labs/dependency-examples/durandal/bower_components/durandal/viewLocator.js create mode 100644 labs/dependency-examples/durandal/bower_components/durandal/viewModel.js create mode 100644 labs/dependency-examples/durandal/bower_components/durandal/viewModelBinder.js create mode 100644 labs/dependency-examples/durandal/bower_components/durandal/widget.js create mode 100644 labs/dependency-examples/durandal/bower_components/jquery/jquery.js create mode 100644 labs/dependency-examples/durandal/bower_components/knockout/knockout.js create mode 100644 labs/dependency-examples/durandal/bower_components/requirejs/require.js create mode 100644 labs/dependency-examples/durandal/bower_components/sammy/sammy.js create mode 100644 labs/dependency-examples/durandal/bower_components/todomvc-common/base.css create mode 100644 labs/dependency-examples/durandal/bower_components/todomvc-common/base.js create mode 100644 labs/dependency-examples/durandal/bower_components/todomvc-common/bg.png create mode 100644 labs/dependency-examples/durandal/css/app.css create mode 100644 labs/dependency-examples/durandal/index.html create mode 100644 labs/dependency-examples/durandal/js/main.js create mode 100644 labs/dependency-examples/durandal/js/viewmodels/entry.js create mode 100644 labs/dependency-examples/durandal/js/viewmodels/list.js create mode 100644 labs/dependency-examples/durandal/js/viewmodels/shell.js create mode 100644 labs/dependency-examples/durandal/js/viewmodels/todoapp.js create mode 100644 labs/dependency-examples/durandal/js/views/entry.html create mode 100644 labs/dependency-examples/durandal/js/views/list.html create mode 100644 labs/dependency-examples/durandal/js/views/shell.html create mode 100644 labs/dependency-examples/durandal/js/views/todoapp.html create mode 100644 labs/dependency-examples/durandal/readme.md create mode 100644 labs/dependency-examples/enyo_backbone/readme.md delete mode 100644 labs/dependency-examples/knockoutjs_require/README.md create mode 100644 labs/dependency-examples/knockoutjs_require/bower.json create mode 100644 labs/dependency-examples/knockoutjs_require/bower_components/knockout.js/knockout.js create mode 100644 labs/dependency-examples/knockoutjs_require/bower_components/requirejs/require.js create mode 100644 labs/dependency-examples/knockoutjs_require/bower_components/todomvc-common/base.css create mode 100644 labs/dependency-examples/knockoutjs_require/bower_components/todomvc-common/base.js create mode 100644 labs/dependency-examples/knockoutjs_require/bower_components/todomvc-common/bg.png delete mode 100644 labs/dependency-examples/knockoutjs_require/js/extends/native.js delete mode 100644 labs/dependency-examples/knockoutjs_require/js/libs/knockout-2.1.0.debug.js delete mode 100644 labs/dependency-examples/knockoutjs_require/js/libs/knockout-2.1.0.js create mode 100644 labs/dependency-examples/knockoutjs_require/readme.md create mode 100644 labs/dependency-examples/somajs_require/bower.json create mode 100644 labs/dependency-examples/somajs_require/bower_components/director/build/director.js rename labs/dependency-examples/{troopjs => somajs_require}/bower_components/requirejs/require.js (100%) create mode 100644 labs/dependency-examples/somajs_require/bower_components/soma-template/build/soma-template.js create mode 100644 labs/dependency-examples/somajs_require/bower_components/soma.js/build/soma.js create mode 100644 labs/dependency-examples/somajs_require/bower_components/todomvc-common/base.css create mode 100644 labs/dependency-examples/somajs_require/bower_components/todomvc-common/base.js create mode 100644 labs/dependency-examples/somajs_require/bower_components/todomvc-common/bg.png create mode 100644 labs/dependency-examples/somajs_require/css/app.css create mode 100644 labs/dependency-examples/somajs_require/index.html create mode 100644 labs/dependency-examples/somajs_require/js/app.js create mode 100644 labs/dependency-examples/somajs_require/js/models/router.js create mode 100644 labs/dependency-examples/somajs_require/js/models/todos.js create mode 100644 labs/dependency-examples/somajs_require/js/views/footer.js create mode 100644 labs/dependency-examples/somajs_require/js/views/header.js create mode 100644 labs/dependency-examples/somajs_require/js/views/main.js create mode 100644 labs/dependency-examples/somajs_require/readme.md create mode 100644 labs/dependency-examples/stapes_require/bower.json create mode 100644 labs/dependency-examples/stapes_require/bower_components/handlebars.js/handlebars.js create mode 100644 labs/dependency-examples/stapes_require/bower_components/requirejs/require.js create mode 100644 labs/dependency-examples/stapes_require/bower_components/stapes/stapes.js create mode 100644 labs/dependency-examples/stapes_require/bower_components/todomvc-common/base.css create mode 100644 labs/dependency-examples/stapes_require/bower_components/todomvc-common/base.js create mode 100644 labs/dependency-examples/stapes_require/bower_components/todomvc-common/bg.png create mode 100644 labs/dependency-examples/stapes_require/bower_components/zepto/zepto.js delete mode 100644 labs/dependency-examples/stapes_require/js/lib/.gitignore delete mode 100644 labs/dependency-examples/stapes_require/js/lib/require.js delete mode 100644 labs/dependency-examples/stapes_require/js/lib/stapes.js delete mode 100644 labs/dependency-examples/stapes_require/js/lib/zepto.js create mode 100644 labs/dependency-examples/stapes_require/readme.md delete mode 100644 labs/dependency-examples/thorax_lumbar/README.md create mode 100644 labs/dependency-examples/thorax_lumbar/bower.json rename labs/dependency-examples/{chaplin-brunch/vendor/scripts/backbone-0.9.2.js => thorax_lumbar/bower_components/backbone/backbone.js} (59%) create mode 100644 labs/dependency-examples/thorax_lumbar/bower_components/handlebars.js/handlebars.js create mode 100644 labs/dependency-examples/thorax_lumbar/bower_components/jquery/jquery.js rename labs/dependency-examples/thorax_lumbar/{src/js/lib => bower_components/lumbar-loader}/lumbar-loader-backbone.js (93%) rename labs/dependency-examples/thorax_lumbar/{src/js/lib => bower_components/lumbar-loader}/lumbar-loader-events.js (94%) rename labs/dependency-examples/thorax_lumbar/{src/js/lib => bower_components/lumbar-loader}/lumbar-loader-localstorage.js (89%) rename labs/dependency-examples/thorax_lumbar/{src/js/lib => bower_components/lumbar-loader}/lumbar-loader-standard.js (95%) rename labs/dependency-examples/thorax_lumbar/{src/js/lib => bower_components/lumbar-loader}/lumbar-loader.js (98%) rename labs/dependency-examples/thorax_lumbar/{src/js/lib => bower_components/script.js/dist}/script.js (74%) create mode 100644 labs/dependency-examples/thorax_lumbar/bower_components/thorax/thorax.js create mode 100644 labs/dependency-examples/thorax_lumbar/bower_components/todomvc-common/base.css create mode 100644 labs/dependency-examples/thorax_lumbar/bower_components/todomvc-common/base.js create mode 100644 labs/dependency-examples/thorax_lumbar/bower_components/todomvc-common/bg.png create mode 100644 labs/dependency-examples/thorax_lumbar/bower_components/underscore/underscore.js create mode 100644 labs/dependency-examples/thorax_lumbar/readme.md delete mode 100644 labs/dependency-examples/thorax_lumbar/src/js/lib/thorax.js delete mode 100644 labs/dependency-examples/troopjs/bower_components/todomvc-common/base.js delete mode 100644 labs/dependency-examples/troopjs/index.html delete mode 100644 labs/dependency-examples/troopjs/js/app.js delete mode 100644 labs/dependency-examples/troopjs/js/config.js delete mode 100644 labs/dependency-examples/troopjs/js/lib/troopjs-bundle.js delete mode 100644 labs/dependency-examples/troopjs/js/widget/application.js delete mode 100644 labs/dependency-examples/troopjs/js/widget/clear.js delete mode 100644 labs/dependency-examples/troopjs/js/widget/count.js delete mode 100644 labs/dependency-examples/troopjs/js/widget/create.js delete mode 100644 labs/dependency-examples/troopjs/js/widget/display.js delete mode 100644 labs/dependency-examples/troopjs/js/widget/escape.js delete mode 100644 labs/dependency-examples/troopjs/js/widget/filters.js delete mode 100644 labs/dependency-examples/troopjs/js/widget/item.html delete mode 100644 labs/dependency-examples/troopjs/js/widget/list.js delete mode 100644 labs/dependency-examples/troopjs/js/widget/mark.js create mode 100644 labs/dependency-examples/troopjs_require/bower.json create mode 100644 labs/dependency-examples/troopjs_require/bower_components/jquery/jquery.js create mode 100644 labs/dependency-examples/troopjs_require/bower_components/requirejs/require.js create mode 100644 labs/dependency-examples/troopjs_require/bower_components/todomvc-common/base.css create mode 100644 labs/dependency-examples/troopjs_require/bower_components/todomvc-common/base.js create mode 100644 labs/dependency-examples/troopjs_require/bower_components/todomvc-common/bg.png create mode 100644 labs/dependency-examples/troopjs_require/bower_components/troopjs-bundle/maxi.js rename labs/dependency-examples/{troopjs => troopjs_require}/css/app.css (73%) create mode 100644 labs/dependency-examples/troopjs_require/index.html create mode 100644 labs/dependency-examples/troopjs_require/js/widget/clear.js create mode 100644 labs/dependency-examples/troopjs_require/js/widget/count.js create mode 100644 labs/dependency-examples/troopjs_require/js/widget/create.js create mode 100644 labs/dependency-examples/troopjs_require/js/widget/display.js create mode 100644 labs/dependency-examples/troopjs_require/js/widget/filters.js create mode 100644 labs/dependency-examples/troopjs_require/js/widget/item.html create mode 100644 labs/dependency-examples/troopjs_require/js/widget/list.js create mode 100644 labs/dependency-examples/troopjs_require/js/widget/mark.js create mode 100644 labs/dependency-examples/troopjs_require/readme.md create mode 100644 learn.json create mode 100644 learn.template.json create mode 100644 tasks/Gruntfile.js create mode 100644 tasks/package.json rename template/{component.json => bower.json} (100%) create mode 100644 template/bower_components/todomvc-common/base.css create mode 100644 template/bower_components/todomvc-common/base.js create mode 100644 template/bower_components/todomvc-common/bg.png delete mode 100644 template/components/todomvc-common/base.js create mode 100644 vanilla-examples/vanillajs/bower.json create mode 100644 vanilla-examples/vanillajs/bower_components/director/build/director.js create mode 100644 vanilla-examples/vanillajs/bower_components/todomvc-common/base.css create mode 100644 vanilla-examples/vanillajs/bower_components/todomvc-common/base.js create mode 100644 vanilla-examples/vanillajs/bower_components/todomvc-common/bg.png create mode 100644 vanilla-examples/vanillajs/js/controller.js create mode 100644 vanilla-examples/vanillajs/js/helpers.js create mode 100644 vanilla-examples/vanillajs/js/model.js create mode 100644 vanilla-examples/vanillajs/js/store.js create mode 100644 vanilla-examples/vanillajs/js/view.js create mode 100644 vanilla-examples/vanillajs/readme.md diff --git a/.gitignore b/.gitignore index e43b0f9889..3a0553dc58 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .DS_Store +tasks/node_modules diff --git a/.jshintrc b/.jshintrc index d1ea1ef0b2..5db60ad4ad 100644 --- a/.jshintrc +++ b/.jshintrc @@ -1,7 +1,6 @@ { "node": true, "browser": true, - "es5": true, "esnext": true, "bitwise": true, "camelcase": true, diff --git a/CNAME b/CNAME index f95c6169f4..26e56f118e 100644 --- a/CNAME +++ b/CNAME @@ -1 +1 @@ -todomvc.com \ No newline at end of file +todomvc.com diff --git a/architecture-examples/agilityjs/bower_components/todomvc-common/base.css b/architecture-examples/agilityjs/bower_components/todomvc-common/base.css index 8d1db3a696..3e6bfaf38d 100644 --- a/architecture-examples/agilityjs/bower_components/todomvc-common/base.css +++ b/architecture-examples/agilityjs/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -412,3 +412,144 @@ label[for='toggle-all'] { .hidden{ display:none; } + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/architecture-examples/agilityjs/bower_components/todomvc-common/base.js b/architecture-examples/agilityjs/bower_components/todomvc-common/base.js index 3fd166d061..099da60dd1 100644 --- a/architecture-examples/agilityjs/bower_components/todomvc-common/base.js +++ b/architecture-examples/agilityjs/bower_components/todomvc-common/base.js @@ -1,38 +1,209 @@ (function () { 'use strict'; + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + if (location.hostname === 'todomvc.com') { window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); } - function getSourcePath() { - // If accessed via addyosmani.github.io/todomvc/, strip the project path. - if (location.hostname.indexOf('github.io') > 0) { - return location.pathname.replace(/todomvc\//, ''); + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); } - return location.pathname; } - function appendSourceLink() { - var sourceLink = document.createElement('a'); - var paragraph = document.createElement('p'); - var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } - if (footer) { - sourceLink.href = urlBase + getSourcePath(); - sourceLink.appendChild(document.createTextNode('Check out the source')); - paragraph.appendChild(sourceLink); - footer.appendChild(paragraph); + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; } - function redirect() { - if (location.hostname === 'addyosmani.github.io') { - location.href = location.href.replace('addyosmani.github.io/todomvc', 'todomvc.com'); + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); } } - appendSourceLink(); + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + redirect(); + getFile('learn.json', Learn); })(); diff --git a/architecture-examples/agilityjs/index.html b/architecture-examples/agilityjs/index.html index 9a50134ada..6e1014090b 100644 --- a/architecture-examples/agilityjs/index.html +++ b/architecture-examples/agilityjs/index.html @@ -1,8 +1,8 @@ - + - + Agility.js • TodoMVC diff --git a/architecture-examples/agilityjs/readme.md b/architecture-examples/agilityjs/readme.md new file mode 100644 index 0000000000..f434e7644e --- /dev/null +++ b/architecture-examples/agilityjs/readme.md @@ -0,0 +1,33 @@ +# Agility.js TodoMVC Example + +> [Agility.js](http://agilityjs.com) is an MVC library for Javascript that lets you write maintainable and reusable browser code without the verbose or infrastructural overhead found in other MVC libraries. The goal is to enable developers to write web apps at least as quickly as with jQuery, while simplifying long-term maintainability through MVC objects. + +> _[Agility.js - agilityjs.com](http://agilityjs.com)_ + + +## Learning Agility.js + +The [Agility.js website](http://agilityjs.com) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Official Documentation](http://agilityjs.com/docs/docs.html) +* [Try it out on JSBin](http://jsbin.com/agility/224/edit) +* [Applications built with Agility.js](http://agilityjs.com/docs/gallery.html) + +Articles and guides from the community: + +* [Step by step from jQuery to Agility.js](https://gist.github.com/pindia/3166678) + +Get help from other Agility.js users: + +* [Google Groups mailing list](http://groups.google.com/group/agilityjs) +* [agility.js on Stack Overflow](http://stackoverflow.com/questions/tagged/agility.js) +* [Agility.js on Twitter](https://twitter.com/agilityjs) +* [Agility.js on Google +](https://plus.google.com/116251025970928820842/posts) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ + + +## Credit +This TodoMVC application was created by [tshm](https://github.com/tshm). diff --git a/architecture-examples/angularjs-perf/bower.json b/architecture-examples/angularjs-perf/bower.json index f910e5194a..5c53d932df 100644 --- a/architecture-examples/angularjs-perf/bower.json +++ b/architecture-examples/angularjs-perf/bower.json @@ -2,7 +2,7 @@ "name": "todomvc-angular-perf", "version": "0.0.0", "dependencies": { - "angular": "~1.0.5", + "angular": "~1.0.7", "todomvc-common": "~0.1.4" } } diff --git a/architecture-examples/angularjs-perf/bower_components/angular/angular.js b/architecture-examples/angularjs-perf/bower_components/angular/angular.js index 68b33c7f92..a860c8594f 100644 --- a/architecture-examples/angularjs-perf/bower_components/angular/angular.js +++ b/architecture-examples/angularjs-perf/bower_components/angular/angular.js @@ -1,5 +1,5 @@ /** - * @license AngularJS v1.0.5 + * @license AngularJS v1.0.7 * (c) 2010-2012 Google, Inc. http://angularjs.org * License: MIT */ @@ -34,12 +34,12 @@ var uppercase = function(string){return isString(string) ? string.toUpperCase() var manualLowercase = function(s) { return isString(s) - ? s.replace(/[A-Z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) | 32);}) + ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);}) : s; }; var manualUppercase = function(s) { return isString(s) - ? s.replace(/[a-z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) & ~32);}) + ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);}) : s; }; @@ -52,8 +52,6 @@ if ('i' !== 'I'.toLowerCase()) { uppercase = manualUppercase; } -function fromCharCode(code) {return String.fromCharCode(code);} - var /** holds major version number for IE or NaN for real browsers */ msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]), @@ -69,6 +67,29 @@ var /** holds major version number for IE or NaN for real browsers */ nodeName_, uid = ['0', '0', '0']; + +/** + * @private + * @param {*} obj + * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...) + */ +function isArrayLike(obj) { + if (!obj || (typeof obj.length !== 'number')) return false; + + // We have on object which has length property. Should we treat it as array? + if (typeof obj.hasOwnProperty != 'function' && + typeof obj.constructor != 'function') { + // This is here for IE8: it is a bogus object treat it as array; + return true; + } else { + return obj instanceof JQLite || // JQLite + (jQuery && obj instanceof jQuery) || // jQuery + toString.call(obj) !== '[object Object]' || // some browser native object + typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj) + } +} + + /** * @ngdoc function * @name angular.forEach @@ -96,30 +117,6 @@ var /** holds major version number for IE or NaN for real browsers */ * @param {Object=} context Object to become context (`this`) for the iterator function. * @returns {Object|Array} Reference to `obj`. */ - - -/** - * @private - * @param {*} obj - * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...) - */ -function isArrayLike(obj) { - if (!obj || (typeof obj.length !== 'number')) return false; - - // We have on object which has length property. Should we treat it as array? - if (typeof obj.hasOwnProperty != 'function' && - typeof obj.constructor != 'function') { - // This is here for IE8: it is a bogus object treat it as array; - return true; - } else { - return obj instanceof JQLite || // JQLite - (jQuery && obj instanceof jQuery) || // jQuery - toString.call(obj) !== '[object Object]' || // some browser native object - typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj) - } -} - - function forEach(obj, iterator, context) { var key; if (obj) { @@ -203,6 +200,21 @@ function nextUid() { return uid.join(''); } + +/** + * Set or clear the hashkey for an object. + * @param obj object + * @param h the hashkey (!truthy to delete the hashkey) + */ +function setHashKey(obj, h) { + if (h) { + obj.$$hashKey = h; + } + else { + delete obj.$$hashKey; + } +} + /** * @ngdoc function * @name angular.extend @@ -214,8 +226,10 @@ function nextUid() { * * @param {Object} dst Destination object. * @param {...Object} src Source object(s). + * @returns {Object} Reference to `dst`. */ function extend(dst) { + var h = dst.$$hashKey; forEach(arguments, function(obj){ if (obj !== dst) { forEach(obj, function(value, key){ @@ -223,6 +237,8 @@ function extend(dst) { }); } }); + + setHashKey(dst,h); return dst; } @@ -577,12 +593,14 @@ function copy(source, destination){ destination.push(copy(source[i])); } } else { + var h = destination.$$hashKey; forEach(destination, function(value, key){ delete destination[key]; }); for ( var key in source) { destination[key] = copy(source[key]); } + setHashKey(destination,h); } } return destination; @@ -622,7 +640,7 @@ function shallowCopy(src, dst) { * During a property comparision, properties of `function` type and properties with names * that begin with `$` are ignored. * - * Scope and DOMWindow objects are being compared only be identify (`===`). + * Scope and DOMWindow objects are being compared only by identify (`===`). * * @param {*} o1 Object or value to compare. * @param {*} o2 Object or value to compare. @@ -682,7 +700,7 @@ function sliceArgs(args, startIndex) { * * @description * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for - * `fn`). You can supply optional `args` that are are prebound to the function. This feature is also + * `fn`). You can supply optional `args` that are prebound to the function. This feature is also * known as [function currying](http://en.wikipedia.org/wiki/Currying). * * @param {Object} self Context which `fn` should be evaluated in. @@ -861,7 +879,7 @@ function encodeUriQuery(val, pctEncodeSpaces) { replace(/%3A/gi, ':'). replace(/%24/g, '$'). replace(/%2C/gi, ','). - replace((pctEncodeSpaces ? null : /%20/g), '+'); + replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); } @@ -875,7 +893,7 @@ function encodeUriQuery(val, pctEncodeSpaces) { * * @description * - * Use this directive to auto-bootstrap on application. Only + * Use this directive to auto-bootstrap an application. Only * one directive can be used per HTML document. The directive * designates the root of the application and is typically placed * at the root of the page. @@ -950,22 +968,38 @@ function angularInit(element, bootstrap) { * @returns {AUTO.$injector} Returns the newly created injector for this app. */ function bootstrap(element, modules) { - element = jqLite(element); - modules = modules || []; - modules.unshift(['$provide', function($provide) { - $provide.value('$rootElement', element); - }]); - modules.unshift('ng'); - var injector = createInjector(modules); - injector.invoke( - ['$rootScope', '$rootElement', '$compile', '$injector', function(scope, element, compile, injector){ - scope.$apply(function() { - element.data('$injector', injector); - compile(element)(scope); - }); - }] - ); - return injector; + var resumeBootstrapInternal = function() { + element = jqLite(element); + modules = modules || []; + modules.unshift(['$provide', function($provide) { + $provide.value('$rootElement', element); + }]); + modules.unshift('ng'); + var injector = createInjector(modules); + injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', + function(scope, element, compile, injector) { + scope.$apply(function() { + element.data('$injector', injector); + compile(element)(scope); + }); + }] + ); + return injector; + }; + + var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; + + if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) { + return resumeBootstrapInternal(); + } + + window.name = window.name.replace(NG_DEFER_BOOTSTRAP, ''); + angular.resumeBootstrap = function(extraModules) { + forEach(extraModules, function(module) { + modules.push(module); + }); + resumeBootstrapInternal(); + }; } var SNAKE_CASE_REGEXP = /[A-Z]/g; @@ -998,7 +1032,7 @@ function bindJQuery() { } /** - * throw error of the argument is falsy. + * throw error if the argument is falsy. */ function assertArg(arg, name, reason) { if (!arg) { @@ -1279,11 +1313,11 @@ function setupModuleLoader(window) { * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". */ var version = { - full: '1.0.5', // all of these placeholder strings will be replaced by rake's - major: 1, // compile task + full: '1.0.7', // all of these placeholder strings will be replaced by grunt's + major: 1, // package task minor: 0, - dot: 5, - codeName: 'flatulent-propulsion' + dot: 7, + codeName: 'monochromatic-rainbow' }; @@ -1428,18 +1462,18 @@ function publishExternalAPI(angular){ * - [after()](http://api.jquery.com/after/) * - [append()](http://api.jquery.com/append/) * - [attr()](http://api.jquery.com/attr/) - * - [bind()](http://api.jquery.com/bind/) - * - [children()](http://api.jquery.com/children/) + * - [bind()](http://api.jquery.com/bind/) - Does not support namespaces + * - [children()](http://api.jquery.com/children/) - Does not support selectors * - [clone()](http://api.jquery.com/clone/) * - [contents()](http://api.jquery.com/contents/) * - [css()](http://api.jquery.com/css/) * - [data()](http://api.jquery.com/data/) * - [eq()](http://api.jquery.com/eq/) - * - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name. + * - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name * - [hasClass()](http://api.jquery.com/hasClass/) * - [html()](http://api.jquery.com/html/) - * - [next()](http://api.jquery.com/next/) - * - [parent()](http://api.jquery.com/parent/) + * - [next()](http://api.jquery.com/next/) - Does not support selectors + * - [parent()](http://api.jquery.com/parent/) - Does not support selectors * - [prepend()](http://api.jquery.com/prepend/) * - [prop()](http://api.jquery.com/prop/) * - [ready()](http://api.jquery.com/ready/) @@ -1451,7 +1485,7 @@ function publishExternalAPI(angular){ * - [text()](http://api.jquery.com/text/) * - [toggleClass()](http://api.jquery.com/toggleClass/) * - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Doesn't pass native event objects to handlers. - * - [unbind()](http://api.jquery.com/unbind/) + * - [unbind()](http://api.jquery.com/unbind/) - Does not support namespaces * - [val()](http://api.jquery.com/val/) * - [wrap()](http://api.jquery.com/wrap/) * @@ -1998,23 +2032,43 @@ forEach({ if (!eventFns) { if (type == 'mouseenter' || type == 'mouseleave') { - var counter = 0; + var contains = document.body.contains || document.body.compareDocumentPosition ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; - events.mouseenter = []; - events.mouseleave = []; + events[type] = []; + + // Refer to jQuery's implementation of mouseenter & mouseleave + // Read about mouseenter and mouseleave: + // http://www.quirksmode.org/js/events_mouse.html#link8 + var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"} + bindFn(element, eventmap[type], function(event) { + var ret, target = this, related = event.relatedTarget; + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !contains(target, related)) ){ + handle(event, type); + } - bindFn(element, 'mouseover', function(event) { - counter++; - if (counter == 1) { - handle(event, 'mouseenter'); - } - }); - bindFn(element, 'mouseout', function(event) { - counter --; - if (counter == 0) { - handle(event, 'mouseleave'); - } }); + } else { addEventListenerFn(element, type, handle); events[type] = []; @@ -2330,7 +2384,7 @@ function annotate(fn) { } } else if (isArray(fn)) { last = fn.length - 1; - assertArgFn(fn[last], 'fn') + assertArgFn(fn[last], 'fn'); $inject = fn.slice(0, last); } else { assertArgFn(fn, 'fn', true); @@ -2364,19 +2418,19 @@ function annotate(fn) { * # Injection Function Annotation * * JavaScript does not have annotations, and annotations are needed for dependency injection. The - * following ways are all valid way of annotating function with injection arguments and are equivalent. + * following are all valid ways of annotating function with injection arguments and are equivalent. * *
  *   // inferred (only works if code not minified/obfuscated)
- *   $inject.invoke(function(serviceA){});
+ *   $injector.invoke(function(serviceA){});
  *
  *   // annotated
  *   function explicit(serviceA) {};
  *   explicit.$inject = ['serviceA'];
- *   $inject.invoke(explicit);
+ *   $injector.invoke(explicit);
  *
  *   // inline
- *   $inject.invoke(['serviceA', function(serviceA){}]);
+ *   $injector.invoke(['serviceA', function(serviceA){}]);
  * 
* * ## Inference @@ -2493,7 +2547,7 @@ function annotate(fn) { * // ... * }; * tmpFn.$inject = ['$compile', '$rootScope']; - * injector.invoke(tempFn); + * injector.invoke(tmpFn); * * // To better support inline function the inline annotation is supported * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) { @@ -2522,7 +2576,7 @@ function annotate(fn) { * @description * * Use `$provide` to register new providers with the `$injector`. The providers are the factories for the instance. - * The providers share the same name as the instance they create with the `Provider` suffixed to them. + * The providers share the same name as the instance they create with `Provider` suffixed to them. * * A provider is an object with a `$get()` method. The injector calls the `$get` method to create a new instance of * a service. The Provider can have additional methods which would allow for configuration of the provider. @@ -2546,7 +2600,7 @@ function annotate(fn) { * * beforeEach(module(function($provide) { * $provide.provider('greet', GreetProvider); - * }); + * })); * * it('should greet', inject(function(greet) { * expect(greet('angular')).toEqual('Hello angular!'); @@ -2559,9 +2613,7 @@ function annotate(fn) { * inject(function(greet) { * expect(greet('angular')).toEqual('Ahoj angular!'); * }); - * )}; - * - * }); + * }); * */ @@ -2655,7 +2707,7 @@ function annotate(fn) { * * @param {string} name The name of the service to decorate. * @param {function()} decorator This function will be invoked when the service needs to be - * instanciated. The function is called using the {@link AUTO.$injector#invoke + * instantiated. The function is called using the {@link AUTO.$injector#invoke * injector.invoke} method and is therefore fully injectable. Local injection arguments: * * * `$delegate` - The original service instance, which can be monkey patched, configured, @@ -2855,6 +2907,8 @@ function createInjector(modulesToLoad) { var Constructor = function() {}, instance, returnedValue; + // Check if Type is annotated and use just the given function at n-1 as parameter + // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]); Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype; instance = new Constructor(); returnedValue = invoke(Type, instance, locals); @@ -2870,6 +2924,7 @@ function createInjector(modulesToLoad) { }; } } + /** * @ngdoc function * @name ng.$anchorScroll @@ -3234,7 +3289,13 @@ function Browser(window, document, $log, $sniffer) { cookie = cookieArray[i]; index = cookie.indexOf('='); if (index > 0) { //ignore nameless cookies - lastCookies[unescape(cookie.substring(0, index))] = unescape(cookie.substring(index + 1)); + var name = unescape(cookie.substring(0, index)); + // the first value that is seen for a cookie is the most + // specific one. values for the same cookie name that + // follow are for less specific paths. + if (lastCookies[name] === undefined) { + lastCookies[name] = unescape(cookie.substring(index + 1)); + } } } } @@ -3298,6 +3359,7 @@ function $BrowserProvider(){ return new Browser($window, $document, $log, $sniffer); }]; } + /** * @ngdoc object * @name ng.$cacheFactory @@ -3625,7 +3687,7 @@ function $CompileProvider($provide) { COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/, CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/, MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ', - urlSanitizationWhitelist = /^\s*(https?|ftp|mailto):/; + urlSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/; /** @@ -3827,7 +3889,7 @@ function $CompileProvider($provide) { function compile($compileNodes, transcludeFn, maxPriority) { if (!($compileNodes instanceof jqLite)) { - // jquery always rewraps, where as we need to preserve the original selector so that we can modify it. + // jquery always rewraps, whereas we need to preserve the original selector so that we can modify it. $compileNodes = jqLite($compileNodes); } // We can not compile top level text elements since text nodes can be merged and we will @@ -3879,7 +3941,7 @@ function $CompileProvider($provide) { * functions return values - the linking functions - are combined into a composite linking * function, which is the a linking function for the node. * - * @param {NodeList} nodeList an array of nodes to compile + * @param {NodeList} nodeList an array of nodes or NodeList to compile * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the * scope argument is auto-generated to the new child of the transcluded parent scope. * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then the @@ -3902,7 +3964,7 @@ function $CompileProvider($provide) { ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement) : null; - childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes.length) + childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes || !nodeList[i].childNodes.length) ? null : compileNodes(nodeList[i].childNodes, nodeLinkFn ? nodeLinkFn.transclude : transcludeFn); @@ -4038,9 +4100,9 @@ function $CompileProvider($provide) { /** - * Once the directives have been collected their compile functions is executed. This method + * Once the directives have been collected, their compile functions are executed. This method * is responsible for inlining directive templates as well as terminating the application - * of the directives if the terminal directive has been reached.. + * of the directives if the terminal directive has been reached. * * @param {Array} directives Array of collected directives to execute their compile function. * this needs to be pre-sorted by priority order. @@ -4048,11 +4110,11 @@ function $CompileProvider($provide) { * @param {Object} templateAttrs The shared attribute function * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the * scope argument is auto-generated to the new child of the transcluded parent scope. - * @param {DOMElement} $rootElement If we are working on the root of the compile tree then this - * argument has the root jqLite array so that we can replace widgets on it. + * @param {JQLite} jqCollection If we are working on the root of the compile tree then this + * argument has the root jqLite array so that we can replace nodes on it. * @returns linkFn */ - function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, $rootElement) { + function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection) { var terminalPriority = -Number.MAX_VALUE, preLinkFns = [], postLinkFns = [], @@ -4106,7 +4168,7 @@ function $CompileProvider($provide) { $compileNode = templateAttrs.$$element = jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' ')); compileNode = $compileNode[0]; - replaceWith($rootElement, jqLite($template[0]), compileNode); + replaceWith(jqCollection, jqLite($template[0]), compileNode); childTranscludeFn = compile($template, transcludeFn, terminalPriority); } else { $template = jqLite(JQLiteClone(compileNode)).contents(); @@ -4130,7 +4192,7 @@ function $CompileProvider($provide) { throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue); } - replaceWith($rootElement, $compileNode, compileNode); + replaceWith(jqCollection, $compileNode, compileNode); var newTemplateAttrs = {$attr: {}}; @@ -4158,7 +4220,7 @@ function $CompileProvider($provide) { assertNoDuplicate('template', templateDirective, directive, $compileNode); templateDirective = directive; nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), - nodeLinkFn, $compileNode, templateAttrs, $rootElement, directive.replace, + nodeLinkFn, $compileNode, templateAttrs, jqCollection, directive.replace, childTranscludeFn); ii = directives.length; } else if (directive.compile) { @@ -4291,7 +4353,7 @@ function $CompileProvider($provide) { parentGet = $parse(attrs[attrName]); scope[scopeName] = function(locals) { return parentGet(parentScope, locals); - } + }; break; } @@ -4461,7 +4523,7 @@ function $CompileProvider($provide) { directives.unshift(derivedSyncDirective); afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn); - afterTemplateChildLinkFn = compileNodes($compileNode.contents(), childTranscludeFn); + afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn); while(linkQueue.length) { @@ -4726,7 +4788,7 @@ function $ControllerProvider() { * @description * `$controller` service is responsible for instantiating controllers. * - * It's just simple call to {@link AUTO.$injector $injector}, but extracted into + * It's just a simple call to {@link AUTO.$injector $injector}, but extracted into * a service, so that one can override this service with {@link https://gist.github.com/1649788 * BC version}. */ @@ -4779,7 +4841,7 @@ function $DocumentProvider(){ * */ function $ExceptionHandlerProvider() { - this.$get = ['$log', function($log){ + this.$get = ['$log', function($log) { return function(exception, cause) { $log.error.apply($log, arguments); }; @@ -4967,7 +5029,7 @@ function $InterpolateProvider() { }]; } -var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/, +var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/, PATH_MATCH = /^([^\?#]*)?(\?([^#]*))?(#(.*))?$/, HASH_MATCH = PATH_MATCH, DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21}; @@ -5046,7 +5108,8 @@ function convertToHashbangUrl(url, basePath, hashPrefix) { var match = matchUrl(url); // already hashbang url - if (decodeURIComponent(match.path) == basePath) { + if (decodeURIComponent(match.path) == basePath && !isUndefined(match.hash) && + match.hash.indexOf(hashPrefix) === 0) { return url; // convert html5 url -> hashbang url } else { @@ -5543,6 +5606,10 @@ function $LocationProvider(){ // update $location when $browser url changes $browser.onUrlChange(function(newUrl) { if ($location.absUrl() != newUrl) { + if ($rootScope.$broadcast('$locationChangeStart', newUrl, $location.absUrl()).defaultPrevented) { + $browser.url($location.absUrl()); + return; + } $rootScope.$evalAsync(function() { var oldUrl = $location.absUrl(); @@ -5851,10 +5918,10 @@ function lex(text, csp){ function readIdent() { var ident = "", start = index, - lastDot, peekIndex, methodName; + lastDot, peekIndex, methodName, ch; while (index < text.length) { - var ch = text.charAt(index); + ch = text.charAt(index); if (ch == '.' || isIdent(ch) || isNumber(ch)) { if (ch == '.') lastDot = index; ident += ch; @@ -5868,7 +5935,7 @@ function lex(text, csp){ if (lastDot) { peekIndex = index; while(peekIndex < text.length) { - var ch = text.charAt(peekIndex); + ch = text.charAt(peekIndex); if (ch == '(') { methodName = ident.substr(lastDot - start + 1); ident = ident.substr(0, lastDot - start); @@ -6121,8 +6188,8 @@ function parser(text, json, $filter, csp){ text.substring(0, token.index) + "] can not be assigned to", token); } right = logicalOR(); - return function(self, locals){ - return left.assign(self, right(self, locals), locals); + return function(scope, locals){ + return left.assign(scope, right(scope, locals), locals); }; } else { return left; @@ -6239,12 +6306,12 @@ function parser(text, json, $filter, csp){ var field = expect().text; var getter = getterFn(field, csp); return extend( - function(self, locals) { - return getter(object(self, locals), locals); + function(scope, locals, self) { + return getter(self || object(scope, locals), locals); }, { - assign:function(self, value, locals) { - return setter(object(self, locals), field, value); + assign:function(scope, value, locals) { + return setter(object(scope, locals), field, value); } } ); @@ -6285,14 +6352,14 @@ function parser(text, json, $filter, csp){ } while (expect(',')); } consume(')'); - return function(self, locals){ + return function(scope, locals){ var args = [], - context = contextGetter ? contextGetter(self, locals) : self; + context = contextGetter ? contextGetter(scope, locals) : scope; for ( var i = 0; i < argsFn.length; i++) { - args.push(argsFn[i](self, locals)); + args.push(argsFn[i](scope, locals)); } - var fnPtr = fn(self, locals) || noop; + var fnPtr = fn(scope, locals, context) || noop; // IE stupidity! return fnPtr.apply ? fnPtr.apply(context, args) @@ -6334,8 +6401,7 @@ function parser(text, json, $filter, csp){ var object = {}; for ( var i = 0; i < keyValues.length; i++) { var keyValue = keyValues[i]; - var value = keyValue.value(self, locals); - object[keyValue.key] = value; + object[keyValue.key] = keyValue.value(self, locals); } return object; }; @@ -6457,7 +6523,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4) { } return pathVal; }; -}; +} function getterFn(path, csp) { if (getterFnCache.hasOwnProperty(path)) { @@ -6472,7 +6538,7 @@ function getterFn(path, csp) { fn = (pathKeysLength < 6) ? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4]) : function(scope, locals) { - var i = 0, val + var i = 0, val; do { val = cspSafeGetterFn( pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++] @@ -6685,7 +6751,7 @@ function $ParseProvider() { * models and avoiding unnecessary browser repaints, which would result in flickering UI. * - $q promises are recognized by the templating engine in angular, which means that in templates * you can treat promises attached to a scope as if they were the resulting values. - * - Q has many more features that $q, but that comes at a cost of bytes. $q is tiny, but contains + * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains * all the important functionality needed for common async tasks. * * # Testing @@ -6880,10 +6946,7 @@ function qFactory(nextTick, exceptionHandler) { * the promise comes from a source that can't be trusted. * * @param {*} value Value or a promise - * @returns {Promise} Returns a single promise that will be resolved with an array of values, - * each value corresponding to the promise at the same index in the `promises` array. If any of - * the promises is resolved with a rejection, this resulting promise will be resolved with the - * same rejection. + * @returns {Promise} Returns a promise of the passed value or promise */ var when = function(value, callback, errback) { var result = defer(), @@ -7240,8 +7303,9 @@ function $RouteProvider(){ * {@link ng.directive:ngView ngView} listens for the directive * to instantiate the controller and render the view. * + * @param {Object} angularEvent Synthetic event object. * @param {Route} current Current route information. - * @param {Route} previous Previous route information. + * @param {Route|Undefined} previous Previous route information, or undefined if current is first route entered. */ /** @@ -7339,7 +7403,7 @@ function $RouteProvider(){ var next = parseRoute(), last = $route.current; - if (next && last && next.$route === last.$route + if (next && last && next.$$route === last.$$route && equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) { last.params = next.params; copy(last.params, $routeParams); @@ -7418,7 +7482,7 @@ function $RouteProvider(){ match = inherit(route, { params: extend({}, $location.search(), params), pathParams: params}); - match.$route = route; + match.$$route = route; } }); // No route matched; fallback to "otherwise" route @@ -7478,22 +7542,22 @@ function $RouteParamsProvider() { /** * DESIGN NOTES * - * The design decisions behind the scope ware heavily favored for speed and memory consumption. + * The design decisions behind the scope are heavily favored for speed and memory consumption. * * The typical use of scope is to watch the expressions, which most of the time return the same * value as last time so we optimize the operation. * - * Closures construction is expensive from speed as well as memory: - * - no closures, instead ups prototypical inheritance for API + * Closures construction is expensive in terms of speed as well as memory: + * - No closures, instead use prototypical inheritance for API * - Internal state needs to be stored on scope directly, which means that private state is * exposed as $$____ properties * * Loop operations are optimized by using while(count--) { ... } * - this means that in order to keep the same order of execution as addition we have to add - * items to the array at the begging (shift) instead of at the end (push) + * items to the array at the beginning (shift) instead of at the end (push) * * Child scopes are created and removed often - * - Using array would be slow since inserts in meddle are expensive so we use linked list + * - Using an array would be slow since inserts in middle are expensive so we use linked list * * There are few watches then a lot of observers. This is why you don't want the observer to be * implemented in the same way as watch. Watch requires return of initialization function which @@ -7515,7 +7579,7 @@ function $RouteParamsProvider() { * @methodOf ng.$rootScopeProvider * @description * - * Sets the number of digest iteration the scope should attempt to execute before giving up and + * Sets the number of digest iterations the scope should attempt to execute before giving up and * assuming that the model is unstable. * * The current default is 10 iterations. @@ -7795,7 +7859,7 @@ function $RootScopeProvider(){ * @function * * @description - * Process all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children. + * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children. * Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the * `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} until no more listeners are * firing. This means that it is possible to get into an infinite loop. This function will throw @@ -8137,7 +8201,7 @@ function $RootScopeProvider(){ * Afterwards, the event traverses upwards toward the root scope and calls all registered * listeners along the way. The event will stop propagating if one of the listeners cancels it. * - * Any exception emmited from the {@link ng.$rootScope.Scope#$on listeners} will be passed + * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed * onto the {@link ng.$exceptionHandler $exceptionHandler} service. * * @param {string} name Event name to emit. @@ -8206,7 +8270,7 @@ function $RootScopeProvider(){ * Any exception emmited from the {@link ng.$rootScope.Scope#$on listeners} will be passed * onto the {@link ng.$exceptionHandler $exceptionHandler} service. * - * @param {string} name Event name to emit. + * @param {string} name Event name to broadcast. * @param {...*} args Optional set of arguments which will be passed onto the event listeners. * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on} */ @@ -8352,10 +8416,23 @@ function $SnifferProvider() { * @example - - + +
+ + +
+ it('should display the greeting in the input box', function() { + input('greeting').enter('Hello, E2E Tests'); + // If we click the button it will block the test runner + // element(':button').click(); + });
*/ @@ -8508,7 +8585,7 @@ function $HttpProvider() { * * @description * The `$http` service is a core Angular service that facilitates communication with the remote - * HTTP servers via browser's {@link https://developer.mozilla.org/en/xmlhttprequest + * HTTP servers via the browser's {@link https://developer.mozilla.org/en/xmlhttprequest * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}. * * For unit testing applications that use `$http` service, see @@ -8518,13 +8595,13 @@ function $HttpProvider() { * $resource} service. * * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by - * the $q service. While for simple usage patters this doesn't matter much, for advanced usage, - * it is important to familiarize yourself with these apis and guarantees they provide. + * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage + * it is important to familiarize yourself with these APIs and the guarantees they provide. * * * # General usage * The `$http` service is a function which takes a single argument — a configuration object — - * that is used to generate an http request and returns a {@link ng.$q promise} + * that is used to generate an HTTP request and returns a {@link ng.$q promise} * with two $http specific methods: `success` and `error`. * *
@@ -8539,21 +8616,21 @@ function $HttpProvider() {
      *     });
      * 
* - * Since the returned value of calling the $http function is a Promise object, you can also use + * Since the returned value of calling the $http function is a `promise`, you can also use * the `then` method to register callbacks, and these callbacks will receive a single argument – - * an object representing the response. See the api signature and type info below for more + * an object representing the response. See the API signature and type info below for more * details. * - * A response status code that falls in the [200, 300) range is considered a success status and + * A response status code between 200 and 299 is considered a success status and * will result in the success callback being called. Note that if the response is a redirect, * XMLHttpRequest will transparently follow it, meaning that the error callback will not be * called for such responses. * * # Shortcut methods * - * Since all invocation of the $http service require definition of the http method and url and - * POST and PUT requests require response body/data to be provided as well, shortcut methods - * were created to simplify using the api: + * Since all invocations of the $http service require passing in an HTTP method and URL, and + * POST/PUT requests require request data to be provided as well, shortcut methods + * were created: * *
      *   $http.get('/someUrl').success(successCallback);
@@ -8572,25 +8649,25 @@ function $HttpProvider() {
      *
      * # Setting HTTP Headers
      *
-     * The $http service will automatically add certain http headers to all requests. These defaults
+     * The $http service will automatically add certain HTTP headers to all requests. These defaults
      * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
      * object, which currently contains this default configuration:
      *
      * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
      *   - `Accept: application/json, text/plain, * / *`
      *   - `X-Requested-With: XMLHttpRequest`
-     * - `$httpProvider.defaults.headers.post`: (header defaults for HTTP POST requests)
+     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
      *   - `Content-Type: application/json`
-     * - `$httpProvider.defaults.headers.put` (header defaults for HTTP PUT requests)
+     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
      *   - `Content-Type: application/json`
      *
-     * To add or overwrite these defaults, simply add or remove a property from this configuration
+     * To add or overwrite these defaults, simply add or remove a property from these configuration
      * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
-     * with name equal to the lower-cased http method name, e.g.
+     * with the lowercased HTTP method name as the key, e.g.
      * `$httpProvider.defaults.headers.get['My-Header']='value'`.
      *
-     * Additionally, the defaults can be set at runtime via the `$http.defaults` object in a similar
-     * fassion as described above.
+     * Additionally, the defaults can be set at runtime via the `$http.defaults` object in the same
+     * fashion.
      *
      *
      * # Transforming Requests and Responses
@@ -8600,32 +8677,36 @@ function $HttpProvider() {
      *
      * Request transformations:
      *
-     * - if the `data` property of the request config object contains an object, serialize it into
+     * - If the `data` property of the request configuration object contains an object, serialize it into
      *   JSON format.
      *
      * Response transformations:
      *
-     *  - if XSRF prefix is detected, strip it (see Security Considerations section below)
-     *  - if json response is detected, deserialize it using a JSON parser
+     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
+     *  - If JSON response is detected, deserialize it using a JSON parser.
+     *
+     * To globally augment or override the default transforms, modify the `$httpProvider.defaults.transformRequest` and
+     * `$httpProvider.defaults.transformResponse` properties. These properties are by default an
+     * array of transform functions, which allows you to `push` or `unshift` a new transformation function into the
+     * transformation chain. You can also decide to completely override any default transformations by assigning your
+     * transformation functions to these properties directly without the array wrapper.
      *
-     * To override these transformation locally, specify transform functions as `transformRequest`
-     * and/or `transformResponse` properties of the config object. To globally override the default
-     * transforms, override the `$httpProvider.defaults.transformRequest` and
-     * `$httpProvider.defaults.transformResponse` properties of the `$httpProvider`.
+     * Similarly, to locally override the request/response transforms, augment the `transformRequest` and/or
+     * `transformResponse` properties of the configuration object passed into `$http`.
      *
      *
      * # Caching
      *
-     * To enable caching set the configuration property `cache` to `true`. When the cache is
+     * To enable caching, set the configuration property `cache` to `true`. When the cache is
      * enabled, `$http` stores the response from the server in local cache. Next time the
      * response is served from the cache without sending a request to the server.
      *
      * Note that even if the response is served from cache, delivery of the data is asynchronous in
      * the same way that real requests are.
      *
-     * If there are multiple GET requests for the same url that should be cached using the same
+     * If there are multiple GET requests for the same URL that should be cached using the same
      * cache, but the cache is not populated yet, only one request to the server will be made and
-     * the remaining requests will be fulfilled using the response for the first request.
+     * the remaining requests will be fulfilled using the response from the first request.
      *
      *
      * # Response interceptors
@@ -8677,7 +8758,7 @@ function $HttpProvider() {
      * When designing web applications, consider security threats from:
      *
      * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
-     *   JSON Vulnerability}
+     *   JSON vulnerability}
      * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
      *
      * Both server and the client must cooperate in order to eliminate these threats. Angular comes
@@ -8687,8 +8768,8 @@ function $HttpProvider() {
      * ## JSON Vulnerability Protection
      *
      * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
-     * JSON Vulnerability} allows third party web-site to turn your JSON resource URL into
-     * {@link http://en.wikipedia.org/wiki/JSON#JSONP JSONP} request under some conditions. To
+     * JSON vulnerability} allows third party website to turn your JSON resource URL into
+     * {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To
      * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
      * Angular will automatically strip the prefix before processing it as JSON.
      *
@@ -8709,19 +8790,19 @@ function $HttpProvider() {
      * ## Cross Site Request Forgery (XSRF) Protection
      *
      * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
-     * an unauthorized site can gain your user's private data. Angular provides following mechanism
+     * an unauthorized site can gain your user's private data. Angular provides a mechanism
      * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
      * called `XSRF-TOKEN` and sets it as the HTTP header `X-XSRF-TOKEN`. Since only JavaScript that
      * runs on your domain could read the cookie, your server can be assured that the XHR came from
      * JavaScript running on your domain.
      *
      * To take advantage of this, your server needs to set a token in a JavaScript readable session
-     * cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent non-GET requests the
+     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
      * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
-     * that only JavaScript running on your domain could have read the token. The token must be
-     * unique for each user and must be verifiable by the server (to prevent the JavaScript making
+     * that only JavaScript running on your domain could have sent the request. The token must be
+     * unique for each user and must be verifiable by the server (to prevent the JavaScript from making
      * up its own tokens). We recommend that the token is a digest of your site's authentication
-     * cookie with {@link http://en.wikipedia.org/wiki/Rainbow_table salt for added security}.
+     * cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} for added security.
      *
      *
      * @param {object} config Object describing the request to be made and how it should be
@@ -8899,7 +8980,7 @@ function $HttpProvider() {
      * @methodOf ng.$http
      *
      * @description
-     * Shortcut method to perform `GET` request
+     * Shortcut method to perform `GET` request.
      *
      * @param {string} url Relative or absolute URL specifying the destination of the request
      * @param {Object=} config Optional configuration object
@@ -8912,7 +8993,7 @@ function $HttpProvider() {
      * @methodOf ng.$http
      *
      * @description
-     * Shortcut method to perform `DELETE` request
+     * Shortcut method to perform `DELETE` request.
      *
      * @param {string} url Relative or absolute URL specifying the destination of the request
      * @param {Object=} config Optional configuration object
@@ -8925,7 +9006,7 @@ function $HttpProvider() {
      * @methodOf ng.$http
      *
      * @description
-     * Shortcut method to perform `HEAD` request
+     * Shortcut method to perform `HEAD` request.
      *
      * @param {string} url Relative or absolute URL specifying the destination of the request
      * @param {Object=} config Optional configuration object
@@ -8938,7 +9019,7 @@ function $HttpProvider() {
      * @methodOf ng.$http
      *
      * @description
-     * Shortcut method to perform `JSONP` request
+     * Shortcut method to perform `JSONP` request.
      *
      * @param {string} url Relative or absolute URL specifying the destination of the request.
      *                     Should contain `JSON_CALLBACK` string.
@@ -8953,7 +9034,7 @@ function $HttpProvider() {
      * @methodOf ng.$http
      *
      * @description
-     * Shortcut method to perform `POST` request
+     * Shortcut method to perform `POST` request.
      *
      * @param {string} url Relative or absolute URL specifying the destination of the request
      * @param {*} data Request content
@@ -8967,7 +9048,7 @@ function $HttpProvider() {
      * @methodOf ng.$http
      *
      * @description
-     * Shortcut method to perform `PUT` request
+     * Shortcut method to perform `PUT` request.
      *
      * @param {string} url Relative or absolute URL specifying the destination of the request
      * @param {*} data Request content
@@ -9019,7 +9100,7 @@ function $HttpProvider() {
 
 
     /**
-     * Makes the request
+     * Makes the request.
      *
      * !!! ACCESSES CLOSURE VARS:
      * $httpBackend, $config, $log, $rootScope, defaultCache, $http.pendingRequests
@@ -9129,6 +9210,7 @@ function $HttpProvider() {
 
   }];
 }
+
 var XHR = window.XMLHttpRequest || function() {
   try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
   try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
@@ -9365,17 +9447,17 @@ function $TimeoutProvider() {
       * block and delegates any exceptions to
       * {@link ng.$exceptionHandler $exceptionHandler} service.
       *
-      * The return value of registering a timeout function is a promise which will be resolved when
+      * The return value of registering a timeout function is a promise, which will be resolved when
       * the timeout is reached and the timeout function is executed.
       *
-      * To cancel a the timeout request, call `$timeout.cancel(promise)`.
+      * To cancel a timeout request, call `$timeout.cancel(promise)`.
       *
       * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
       * synchronously flush the queue of deferred functions.
       *
-      * @param {function()} fn A function, who's execution should be delayed.
+      * @param {function()} fn A function, whose execution should be delayed.
       * @param {number=} [delay=0] Delay in milliseconds.
-      * @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise
+      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
       * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
       *   promise will be resolved with is the return value of the `fn` function.
@@ -9415,7 +9497,7 @@ function $TimeoutProvider() {
       * @methodOf ng.$timeout
       *
       * @description
-      * Cancels a task associated with the `promise`. As a result of this the promise will be
+      * Cancels a task associated with the `promise`. As a result of this, the promise will be
       * resolved with a rejection.
       *
       * @param {Promise=} promise Promise returned by the `$timeout` function.
@@ -9441,7 +9523,7 @@ function $TimeoutProvider() {
  *
  * Filters are just functions which transform input to an output. However filters need to be Dependency Injected. To
  * achieve this a filter definition consists of a factory function which is annotated with dependencies and is
- * responsible for creating a the filter function.
+ * responsible for creating a filter function.
  *
  * 
  *   // Filter registration
@@ -9503,7 +9585,7 @@ function $TimeoutProvider() {
  *
  * The general syntax in templates is as follows:
  *
- *         {{ expression | [ filter_name ] }}
+ *         {{ expression [| filter_name[:parameter_value] ... ] }}
  *
  * @param {String} name Name of the filter function to retrieve
  * @return {Function} the filter function
@@ -9579,22 +9661,22 @@ function $FilterProvider($provide) {
 
        Search: 
        
-         
+         
-         
+         
NamePhone
NamePhone
{{friend.name}} {{friend.phone}}

Any:
Name only
- Phone only
+ Phone only
- + - +
NamePhone
NamePhone
{{friend.name}} {{friend.phone}}
@@ -9891,6 +9973,7 @@ function padNumber(num, digits, trim) { function dateGetter(name, size, offset, trim) { + offset = offset || 0; return function(date) { var value = date['get' + name](); if (offset > 0 || value > -offset) @@ -9913,7 +9996,8 @@ function timeZoneGetter(date) { var zone = -1 * date.getTimezoneOffset(); var paddedZone = (zone >= 0) ? "+" : ""; - paddedZone += padNumber(zone / 60, 2) + padNumber(Math.abs(zone % 60), 2); + paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) + + padNumber(Math.abs(zone % 60), 2); return paddedZone; } @@ -9979,7 +10063,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+ * * `'ss'`: Second in minute, padded (00-59) * * `'s'`: Second in minute (0-59) * * `'a'`: am/pm marker - * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-1200) + * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200) * * `format` string can also be one of the following predefined * {@link guide/i18n localizable formats}: @@ -10000,7 +10084,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+ * (e.g. `"h o''clock"`). * * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or - * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and it's + * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is * specified in the string input, the time is considered to be in the local timezone. * @param {string=} format Formatting rules (see Description). If not specified, @@ -10291,12 +10375,12 @@ function limitToFilter(){ (^) Phone Number Age - + {{friend.name}} {{friend.phone}} {{friend.age}} - + @@ -11118,8 +11202,8 @@ var inputType = { * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. - * @param {string=} min Sets the `min` validation error key if the value entered is less then `min`. - * @param {string=} max Sets the `max` validation error key if the value entered is greater then `min`. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. * @param {string=} required Sets `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of @@ -11431,6 +11515,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { } else { var timeout; + var deferListener = function() { + if (!timeout) { + timeout = $browser.defer(function() { + listener(); + timeout = null; + }); + } + }; + element.bind('keydown', function(event) { var key = event.keyCode; @@ -11438,16 +11531,16 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { // command modifiers arrows if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return; - if (!timeout) { - timeout = $browser.defer(function() { - listener(); - timeout = null; - }); - } + deferListener(); }); // if user paste into input using mouse, we need "change" event to catch it element.bind('change', listener); + + // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it + if ($sniffer.hasEvent('paste')) { + element.bind('paste cut', deferListener); + } } @@ -11746,7 +11839,7 @@ function checkboxInputType(scope, element, attr, ctrl) { myForm.userName.$valid = {{myForm.userName.$valid}}
myForm.userName.$error = {{myForm.userName.$error}}
myForm.lastName.$valid = {{myForm.lastName.$valid}}
- myForm.userName.$error = {{myForm.lastName.$error}}
+ myForm.lastName.$error = {{myForm.lastName.$error}}
myForm.$valid = {{myForm.$valid}}
myForm.$error.required = {{!!myForm.$error.required}}
myForm.$error.minlength = {{!!myForm.$error.minlength}}
@@ -12009,7 +12102,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ * For example {@link ng.directive:input input} or * {@link ng.directive:select select} directives call it. * - * It internally calls all `formatters` and if resulted value is valid, updates the model and + * It internally calls all `parsers` and if resulted value is valid, updates the model and * calls all registered change listeners. * * @param {string} value Value from the view. @@ -12315,7 +12408,7 @@ var ngValueDirective = function() { * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like * `{{ expression }}` which is similar but less verbose. * - * Once scenario in which the use of `ngBind` is prefered over `{{ expression }}` binding is when + * One scenario in which the use of `ngBind` is preferred over `{{ expression }}` binding is when * it's desirable to put bindings into template that is momentarily displayed by the browser in its * raw state before Angular compiles it. Since `ngBind` is an element attribute, it makes the * bindings invisible to the user while the page is loading. @@ -12456,9 +12549,9 @@ function classDirective(name, selector) { if (name !== 'ngClass') { scope.$watch('$index', function($index, old$index) { - var mod = $index % 2; - if (mod !== old$index % 2) { - if (mod == selector) { + var mod = $index & 1; + if (mod !== old$index & 1) { + if (mod === selector) { addClass(scope.$eval(attr[name])); } else { removeClass(scope.$eval(attr[name])); @@ -12470,12 +12563,12 @@ function classDirective(name, selector) { function ngClassWatchAction(newVal) { if (selector === true || scope.$index % 2 === selector) { - if (oldVal && (newVal !== oldVal)) { + if (oldVal && !equals(newVal,oldVal)) { removeClass(oldVal); } addClass(newVal); } - oldVal = newVal; + oldVal = copy(newVal); } @@ -12601,7 +12694,7 @@ var ngClassOddDirective = classDirective('Odd', 0); * @name ng.directive:ngClassEven * * @description - * The `ngClassOdd` and `ngClassEven` works exactly as + * The `ngClassOdd` and `ngClassEven` directives work exactly as * {@link ng.directive:ngClass ngClass}, except it works in * conjunction with `ngRepeat` and takes affect only on odd (even) rows. * @@ -12659,7 +12752,7 @@ var ngClassEvenDirective = classDirective('Even', 1); * `angular.min.js` files. Following is the css rule: * *
- * [ng\:cloak], [ng-cloak], .ng-cloak {
+ * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
  *   display: none;
  * }
  * 
@@ -12718,8 +12811,7 @@ var ngCloakDirective = ngDirective({ * * Controller — The `ngController` directive specifies a Controller class; the class has * methods that typically express the business logic behind the application. * - * Note that an alternative way to define controllers is via the `{@link ng.$route}` - * service. + * Note that an alternative way to define controllers is via the {@link ng.$route $route} service. * * @element ANY * @scope @@ -12810,16 +12902,32 @@ var ngControllerDirective = [function() { * @name ng.directive:ngCsp * @priority 1000 * + * @element html * @description * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support. - * This directive should be used on the root element of the application (typically the `` - * element or other element with the {@link ng.directive:ngApp ngApp} - * directive). - * - * If enabled the performance of template expression evaluator will suffer slightly, so don't enable - * this mode unless you need it. - * - * @element html + * + * This is necessary when developing things like Google Chrome Extensions. + * + * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things). + * For us to be compatible, we just need to implement the "getterFn" in $parse without violating + * any of these restrictions. + * + * AngularJS uses `Function(string)` generated functions as a speed optimization. By applying `ngCsp` + * it is be possible to opt into the CSP compatible mode. When this mode is on AngularJS will + * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will + * be raised. + * + * In order to use this feature put `ngCsp` directive on the root element of the application. + * + * @example + * This example shows how to apply the `ngCsp` directive to the `html` tag. +
+     
+     
+     ...
+     ...
+     
+   
*/ var ngCspDirective = ['$sniffer', function($sniffer) { @@ -13444,7 +13552,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp if (!isNaN(value)) { //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise, //check it against pluralization rules in $locale service - if (!whens[value]) value = $locale.pluralCat(value - offset); + if (!(value in whens)) value = $locale.pluralCat(value - offset); return whensExpFns[value](scope, element, true); } else { return ''; @@ -13552,7 +13660,7 @@ var ngRepeatDirective = ngDirective({ // Same as lastOrder but it has the current state. It will become the // lastOrder on the next iteration. nextOrder = new HashQueueMap(), - arrayLength, + arrayBound, childScope, key, value, // key/value of iteration array, @@ -13573,7 +13681,7 @@ var ngRepeatDirective = ngDirective({ array = collection || []; } - arrayLength = array.length; + arrayBound = array.length-1; // we are not using forEach for perf reasons (trying to avoid #call) for (index = 0, length = array.length; index < length; index++) { @@ -13610,7 +13718,7 @@ var ngRepeatDirective = ngDirective({ childScope.$index = index; childScope.$first = (index === 0); - childScope.$last = (index === (arrayLength - 1)); + childScope.$last = (index === arrayBound); childScope.$middle = !(childScope.$first || childScope.$last); if (!last) { @@ -13777,11 +13885,13 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) { * @description * Conditionally change the DOM structure. * - * @usageContent - * ... + * @usage + * + * ... * ... * ... * ... + * * * @scope * @param {*} ngSwitch|on expression to match against ng-switch-when. @@ -14175,7 +14285,8 @@ var scriptDirective = ['$templateCache', function($templateCache) { * `select` model to be bound to a non-string value. This is because an option element can currently * be bound to string values only. * - * @param {string} name assignable expression to data-bind to. + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. * @param {string=} required The control is considered valid only if value is entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of @@ -14270,7 +14381,7 @@ var scriptDirective = ['$templateCache', function($templateCache) { var ngOptionsDirective = valueFn({ terminal: true }); var selectDirective = ['$compile', '$parse', function($compile, $parse) { - //00001111100000000000222200000000000000000000003333000000000000044444444444444444000000000555555555555555550000000666666666666666660000000000000007777 + //0000111110000000000022220000000000000000000000333300000000000000444444444444444440000000005555555555555555500000006666666666666666600000000000000077770 var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/, nullModelCtrl = {$setViewValue: noop}; @@ -14542,10 +14653,6 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { if (multiple) { selectedSet = new HashMap(modelValue); - } else if (modelValue === null || nullOption) { - // if we are not multiselect, and we are null then we have to add the nullOption - optionGroups[''].push({selected:modelValue === null, id:'', label:''}); - selectedSet = true; } // We now build up the list of options we need (we merge later) @@ -14570,9 +14677,14 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { selected: selected // determine if we should be selected }); } - if (!multiple && !selectedSet) { - // nothing was selected, we have to insert the undefined item - optionGroups[''].unshift({id:'?', label:'', selected:true}); + if (!multiple) { + if (nullOption || modelValue === null) { + // insert null option if we have a placeholder, or the model is null + optionGroups[''].unshift({id:'', label:'', selected:!selectedSet}); + } else if (!selectedSet) { + // option could not be found, we have to insert the undefined item + optionGroups[''].unshift({id:'?', label:'', selected:true}); + } } // Now we need to update the list of DOM nodes to match the optionGroups we computed above @@ -14616,7 +14728,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { if (existingOption.id !== option.id) { lastElement.val(existingOption.id = option.id); } - if (existingOption.element.selected !== option.selected) { + // lastElement.prop('selected') provided by jQuery has side-effects + if (lastElement[0].selected !== option.selected) { lastElement.prop('selected', (existingOption.selected = option.selected)); } } else { @@ -14719,6 +14832,7 @@ var styleDirective = valueFn({ restrict: 'E', terminal: true }); + //try to bind to jquery now so that one can write angular.element().read() //but we will rebind on bootstrap again. bindJQuery(); diff --git a/architecture-examples/angularjs-perf/bower_components/todomvc-common/base.css b/architecture-examples/angularjs-perf/bower_components/todomvc-common/base.css index 8d1db3a696..3e6bfaf38d 100644 --- a/architecture-examples/angularjs-perf/bower_components/todomvc-common/base.css +++ b/architecture-examples/angularjs-perf/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -412,3 +412,144 @@ label[for='toggle-all'] { .hidden{ display:none; } + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/architecture-examples/angularjs-perf/bower_components/todomvc-common/base.js b/architecture-examples/angularjs-perf/bower_components/todomvc-common/base.js index 3fd166d061..099da60dd1 100644 --- a/architecture-examples/angularjs-perf/bower_components/todomvc-common/base.js +++ b/architecture-examples/angularjs-perf/bower_components/todomvc-common/base.js @@ -1,38 +1,209 @@ (function () { 'use strict'; + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + if (location.hostname === 'todomvc.com') { window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); } - function getSourcePath() { - // If accessed via addyosmani.github.io/todomvc/, strip the project path. - if (location.hostname.indexOf('github.io') > 0) { - return location.pathname.replace(/todomvc\//, ''); + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); } - return location.pathname; } - function appendSourceLink() { - var sourceLink = document.createElement('a'); - var paragraph = document.createElement('p'); - var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } - if (footer) { - sourceLink.href = urlBase + getSourcePath(); - sourceLink.appendChild(document.createTextNode('Check out the source')); - paragraph.appendChild(sourceLink); - footer.appendChild(paragraph); + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; } - function redirect() { - if (location.hostname === 'addyosmani.github.io') { - location.href = location.href.replace('addyosmani.github.io/todomvc', 'todomvc.com'); + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); } } - appendSourceLink(); + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + redirect(); + getFile('learn.json', Learn); })(); diff --git a/architecture-examples/angularjs-perf/index.html b/architecture-examples/angularjs-perf/index.html index fbf7ca7e19..2d7aabecca 100644 --- a/architecture-examples/angularjs-perf/index.html +++ b/architecture-examples/angularjs-perf/index.html @@ -1,11 +1,11 @@ - + - + AngularJS • TodoMVC - +
diff --git a/architecture-examples/angularjs-perf/js/controllers/todoCtrl.js b/architecture-examples/angularjs-perf/js/controllers/todoCtrl.js index 05bc66d242..4285615cf8 100644 --- a/architecture-examples/angularjs-perf/js/controllers/todoCtrl.js +++ b/architecture-examples/angularjs-perf/js/controllers/todoCtrl.js @@ -20,9 +20,7 @@ todomvc.controller('TodoCtrl', function TodoCtrl($scope, $location, todoStorage, $scope.location = $location; $scope.$watch('location.path()', function (path) { - $scope.statusFilter = (path === '/active') ? - { completed: false } : (path === '/completed') ? - { completed: true } : null; + $scope.statusFilter = { '/active': {completed: false}, '/completed': {completed: true} }[path]; }); $scope.$watch('remainingCount == 0', function (val) { @@ -30,12 +28,13 @@ todomvc.controller('TodoCtrl', function TodoCtrl($scope, $location, todoStorage, }); $scope.addTodo = function () { - if ($scope.newTodo.length === 0) { + var newTodo = $scope.newTodo.trim(); + if (newTodo.length === 0) { return; } todos.push({ - title: $scope.newTodo, + title: newTodo, completed: false }); todoStorage.put(todos); @@ -50,6 +49,7 @@ todomvc.controller('TodoCtrl', function TodoCtrl($scope, $location, todoStorage, $scope.doneEditing = function (todo) { $scope.editedTodo = null; + todo.title = todo.title.trim(); if (!todo.title) { $scope.removeTodo(todo); @@ -65,11 +65,7 @@ todomvc.controller('TodoCtrl', function TodoCtrl($scope, $location, todoStorage, }; $scope.todoCompleted = function (todo) { - if (todo.completed) { - $scope.remainingCount--; - } else { - $scope.remainingCount++; - } + $scope.remainingCount += todo.completed ? -1 : 1; todoStorage.put(todos); }; diff --git a/architecture-examples/angularjs-perf/readme.md b/architecture-examples/angularjs-perf/readme.md new file mode 100644 index 0000000000..bde2204ab6 --- /dev/null +++ b/architecture-examples/angularjs-perf/readme.md @@ -0,0 +1,42 @@ +# AngularJS (Performance Optimized) TodoMVC Example + +> HTML is great for declaring static documents, but it falters when we try to use it for declaring dynamic views in web-applications. AngularJS lets you extend HTML vocabulary for your application. The resulting environment is extraordinarily expressive, readable, and quick to develop. + +> _[AngularJS - angularjs.org](http://angularjs.org)_ + + +## Learning AngularJS +The [AngularJS website](http://angularjs.org) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Tutorial](http://docs.angularjs.org/tutorial) +* [API Reference](http://docs.angularjs.org/api) +* [Developer Guide](http://docs.angularjs.org/guide) +* [Applications built with AngularJS](http://builtwith.angularjs.org) +* [Blog](http://blog.angularjs.org) +* [FAQ](http://docs.angularjs.org/misc/faq) +* [AngularJS Meetups](http://www.youtube.com/angularjs) + +Articles and guides from the community: + +* [Code School AngularJS course](http://www.codeschool.com/code_tv/angularjs-part-1) +* [5 Awesome AngularJS Features](http://net.tutsplus.com/tutorials/javascript-ajax/5-awesome-angularjs-features) +* [Using Yeoman with AngularJS](http://briantford.com/blog/angular-yeoman.html) +* [me&ngular - an introduction to MVW](http://stephenplusplus.github.io/meangular) + +Get help from other AngularJS users: + +* [Walkthroughs and Tutorials on YouTube](http://www.youtube.com/playlist?list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz) +* [Google Groups mailing list](https://groups.google.com/forum/?fromgroups#!forum/angular) +* [angularjs on Stack Overflow](http://stackoverflow.com/questions/tagged/angularjs) +* [AngularJS on Twitter](https://twitter.com/angularjs) +* [AngularjS on Google +](https://plus.google.com/+AngularJS/posts) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ + + +## Implementation +The normal AngularJS TodoMVC implemetation performs deep watching of the todos array object. This means that it keeps an in-memory copy of the complete array that is used for dirty checking in order to detect model mutations. For smaller applications such as TodoMVC, this is completely fine as one trades off a little memory and performance for the sake of simplicity. + +In larger more complex applications however, where one might be working with 100s or 1000s of large objects one definitely should avoid using this approach. This implementation of the AngularJS app demonstrates the correct way to approach this problem when working in larger apps. diff --git a/architecture-examples/angularjs/bower.json b/architecture-examples/angularjs/bower.json index 7b080dd1ae..290c525cc8 100644 --- a/architecture-examples/angularjs/bower.json +++ b/architecture-examples/angularjs/bower.json @@ -2,10 +2,10 @@ "name": "todomvc-angular", "version": "0.0.0", "dependencies": { - "angular": "~1.0.5", + "angular": "~1.0.7", "todomvc-common": "~0.1.4" }, "devDependencies": { "angular-mocks": "~1.0.5" } -} \ No newline at end of file +} diff --git a/architecture-examples/angularjs/bower_components/angular/angular.js b/architecture-examples/angularjs/bower_components/angular/angular.js index 68b33c7f92..a860c8594f 100644 --- a/architecture-examples/angularjs/bower_components/angular/angular.js +++ b/architecture-examples/angularjs/bower_components/angular/angular.js @@ -1,5 +1,5 @@ /** - * @license AngularJS v1.0.5 + * @license AngularJS v1.0.7 * (c) 2010-2012 Google, Inc. http://angularjs.org * License: MIT */ @@ -34,12 +34,12 @@ var uppercase = function(string){return isString(string) ? string.toUpperCase() var manualLowercase = function(s) { return isString(s) - ? s.replace(/[A-Z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) | 32);}) + ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);}) : s; }; var manualUppercase = function(s) { return isString(s) - ? s.replace(/[a-z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) & ~32);}) + ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);}) : s; }; @@ -52,8 +52,6 @@ if ('i' !== 'I'.toLowerCase()) { uppercase = manualUppercase; } -function fromCharCode(code) {return String.fromCharCode(code);} - var /** holds major version number for IE or NaN for real browsers */ msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]), @@ -69,6 +67,29 @@ var /** holds major version number for IE or NaN for real browsers */ nodeName_, uid = ['0', '0', '0']; + +/** + * @private + * @param {*} obj + * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...) + */ +function isArrayLike(obj) { + if (!obj || (typeof obj.length !== 'number')) return false; + + // We have on object which has length property. Should we treat it as array? + if (typeof obj.hasOwnProperty != 'function' && + typeof obj.constructor != 'function') { + // This is here for IE8: it is a bogus object treat it as array; + return true; + } else { + return obj instanceof JQLite || // JQLite + (jQuery && obj instanceof jQuery) || // jQuery + toString.call(obj) !== '[object Object]' || // some browser native object + typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj) + } +} + + /** * @ngdoc function * @name angular.forEach @@ -96,30 +117,6 @@ var /** holds major version number for IE or NaN for real browsers */ * @param {Object=} context Object to become context (`this`) for the iterator function. * @returns {Object|Array} Reference to `obj`. */ - - -/** - * @private - * @param {*} obj - * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...) - */ -function isArrayLike(obj) { - if (!obj || (typeof obj.length !== 'number')) return false; - - // We have on object which has length property. Should we treat it as array? - if (typeof obj.hasOwnProperty != 'function' && - typeof obj.constructor != 'function') { - // This is here for IE8: it is a bogus object treat it as array; - return true; - } else { - return obj instanceof JQLite || // JQLite - (jQuery && obj instanceof jQuery) || // jQuery - toString.call(obj) !== '[object Object]' || // some browser native object - typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj) - } -} - - function forEach(obj, iterator, context) { var key; if (obj) { @@ -203,6 +200,21 @@ function nextUid() { return uid.join(''); } + +/** + * Set or clear the hashkey for an object. + * @param obj object + * @param h the hashkey (!truthy to delete the hashkey) + */ +function setHashKey(obj, h) { + if (h) { + obj.$$hashKey = h; + } + else { + delete obj.$$hashKey; + } +} + /** * @ngdoc function * @name angular.extend @@ -214,8 +226,10 @@ function nextUid() { * * @param {Object} dst Destination object. * @param {...Object} src Source object(s). + * @returns {Object} Reference to `dst`. */ function extend(dst) { + var h = dst.$$hashKey; forEach(arguments, function(obj){ if (obj !== dst) { forEach(obj, function(value, key){ @@ -223,6 +237,8 @@ function extend(dst) { }); } }); + + setHashKey(dst,h); return dst; } @@ -577,12 +593,14 @@ function copy(source, destination){ destination.push(copy(source[i])); } } else { + var h = destination.$$hashKey; forEach(destination, function(value, key){ delete destination[key]; }); for ( var key in source) { destination[key] = copy(source[key]); } + setHashKey(destination,h); } } return destination; @@ -622,7 +640,7 @@ function shallowCopy(src, dst) { * During a property comparision, properties of `function` type and properties with names * that begin with `$` are ignored. * - * Scope and DOMWindow objects are being compared only be identify (`===`). + * Scope and DOMWindow objects are being compared only by identify (`===`). * * @param {*} o1 Object or value to compare. * @param {*} o2 Object or value to compare. @@ -682,7 +700,7 @@ function sliceArgs(args, startIndex) { * * @description * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for - * `fn`). You can supply optional `args` that are are prebound to the function. This feature is also + * `fn`). You can supply optional `args` that are prebound to the function. This feature is also * known as [function currying](http://en.wikipedia.org/wiki/Currying). * * @param {Object} self Context which `fn` should be evaluated in. @@ -861,7 +879,7 @@ function encodeUriQuery(val, pctEncodeSpaces) { replace(/%3A/gi, ':'). replace(/%24/g, '$'). replace(/%2C/gi, ','). - replace((pctEncodeSpaces ? null : /%20/g), '+'); + replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); } @@ -875,7 +893,7 @@ function encodeUriQuery(val, pctEncodeSpaces) { * * @description * - * Use this directive to auto-bootstrap on application. Only + * Use this directive to auto-bootstrap an application. Only * one directive can be used per HTML document. The directive * designates the root of the application and is typically placed * at the root of the page. @@ -950,22 +968,38 @@ function angularInit(element, bootstrap) { * @returns {AUTO.$injector} Returns the newly created injector for this app. */ function bootstrap(element, modules) { - element = jqLite(element); - modules = modules || []; - modules.unshift(['$provide', function($provide) { - $provide.value('$rootElement', element); - }]); - modules.unshift('ng'); - var injector = createInjector(modules); - injector.invoke( - ['$rootScope', '$rootElement', '$compile', '$injector', function(scope, element, compile, injector){ - scope.$apply(function() { - element.data('$injector', injector); - compile(element)(scope); - }); - }] - ); - return injector; + var resumeBootstrapInternal = function() { + element = jqLite(element); + modules = modules || []; + modules.unshift(['$provide', function($provide) { + $provide.value('$rootElement', element); + }]); + modules.unshift('ng'); + var injector = createInjector(modules); + injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', + function(scope, element, compile, injector) { + scope.$apply(function() { + element.data('$injector', injector); + compile(element)(scope); + }); + }] + ); + return injector; + }; + + var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; + + if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) { + return resumeBootstrapInternal(); + } + + window.name = window.name.replace(NG_DEFER_BOOTSTRAP, ''); + angular.resumeBootstrap = function(extraModules) { + forEach(extraModules, function(module) { + modules.push(module); + }); + resumeBootstrapInternal(); + }; } var SNAKE_CASE_REGEXP = /[A-Z]/g; @@ -998,7 +1032,7 @@ function bindJQuery() { } /** - * throw error of the argument is falsy. + * throw error if the argument is falsy. */ function assertArg(arg, name, reason) { if (!arg) { @@ -1279,11 +1313,11 @@ function setupModuleLoader(window) { * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". */ var version = { - full: '1.0.5', // all of these placeholder strings will be replaced by rake's - major: 1, // compile task + full: '1.0.7', // all of these placeholder strings will be replaced by grunt's + major: 1, // package task minor: 0, - dot: 5, - codeName: 'flatulent-propulsion' + dot: 7, + codeName: 'monochromatic-rainbow' }; @@ -1428,18 +1462,18 @@ function publishExternalAPI(angular){ * - [after()](http://api.jquery.com/after/) * - [append()](http://api.jquery.com/append/) * - [attr()](http://api.jquery.com/attr/) - * - [bind()](http://api.jquery.com/bind/) - * - [children()](http://api.jquery.com/children/) + * - [bind()](http://api.jquery.com/bind/) - Does not support namespaces + * - [children()](http://api.jquery.com/children/) - Does not support selectors * - [clone()](http://api.jquery.com/clone/) * - [contents()](http://api.jquery.com/contents/) * - [css()](http://api.jquery.com/css/) * - [data()](http://api.jquery.com/data/) * - [eq()](http://api.jquery.com/eq/) - * - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name. + * - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name * - [hasClass()](http://api.jquery.com/hasClass/) * - [html()](http://api.jquery.com/html/) - * - [next()](http://api.jquery.com/next/) - * - [parent()](http://api.jquery.com/parent/) + * - [next()](http://api.jquery.com/next/) - Does not support selectors + * - [parent()](http://api.jquery.com/parent/) - Does not support selectors * - [prepend()](http://api.jquery.com/prepend/) * - [prop()](http://api.jquery.com/prop/) * - [ready()](http://api.jquery.com/ready/) @@ -1451,7 +1485,7 @@ function publishExternalAPI(angular){ * - [text()](http://api.jquery.com/text/) * - [toggleClass()](http://api.jquery.com/toggleClass/) * - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Doesn't pass native event objects to handlers. - * - [unbind()](http://api.jquery.com/unbind/) + * - [unbind()](http://api.jquery.com/unbind/) - Does not support namespaces * - [val()](http://api.jquery.com/val/) * - [wrap()](http://api.jquery.com/wrap/) * @@ -1998,23 +2032,43 @@ forEach({ if (!eventFns) { if (type == 'mouseenter' || type == 'mouseleave') { - var counter = 0; + var contains = document.body.contains || document.body.compareDocumentPosition ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; - events.mouseenter = []; - events.mouseleave = []; + events[type] = []; + + // Refer to jQuery's implementation of mouseenter & mouseleave + // Read about mouseenter and mouseleave: + // http://www.quirksmode.org/js/events_mouse.html#link8 + var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"} + bindFn(element, eventmap[type], function(event) { + var ret, target = this, related = event.relatedTarget; + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !contains(target, related)) ){ + handle(event, type); + } - bindFn(element, 'mouseover', function(event) { - counter++; - if (counter == 1) { - handle(event, 'mouseenter'); - } - }); - bindFn(element, 'mouseout', function(event) { - counter --; - if (counter == 0) { - handle(event, 'mouseleave'); - } }); + } else { addEventListenerFn(element, type, handle); events[type] = []; @@ -2330,7 +2384,7 @@ function annotate(fn) { } } else if (isArray(fn)) { last = fn.length - 1; - assertArgFn(fn[last], 'fn') + assertArgFn(fn[last], 'fn'); $inject = fn.slice(0, last); } else { assertArgFn(fn, 'fn', true); @@ -2364,19 +2418,19 @@ function annotate(fn) { * # Injection Function Annotation * * JavaScript does not have annotations, and annotations are needed for dependency injection. The - * following ways are all valid way of annotating function with injection arguments and are equivalent. + * following are all valid ways of annotating function with injection arguments and are equivalent. * *
  *   // inferred (only works if code not minified/obfuscated)
- *   $inject.invoke(function(serviceA){});
+ *   $injector.invoke(function(serviceA){});
  *
  *   // annotated
  *   function explicit(serviceA) {};
  *   explicit.$inject = ['serviceA'];
- *   $inject.invoke(explicit);
+ *   $injector.invoke(explicit);
  *
  *   // inline
- *   $inject.invoke(['serviceA', function(serviceA){}]);
+ *   $injector.invoke(['serviceA', function(serviceA){}]);
  * 
* * ## Inference @@ -2493,7 +2547,7 @@ function annotate(fn) { * // ... * }; * tmpFn.$inject = ['$compile', '$rootScope']; - * injector.invoke(tempFn); + * injector.invoke(tmpFn); * * // To better support inline function the inline annotation is supported * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) { @@ -2522,7 +2576,7 @@ function annotate(fn) { * @description * * Use `$provide` to register new providers with the `$injector`. The providers are the factories for the instance. - * The providers share the same name as the instance they create with the `Provider` suffixed to them. + * The providers share the same name as the instance they create with `Provider` suffixed to them. * * A provider is an object with a `$get()` method. The injector calls the `$get` method to create a new instance of * a service. The Provider can have additional methods which would allow for configuration of the provider. @@ -2546,7 +2600,7 @@ function annotate(fn) { * * beforeEach(module(function($provide) { * $provide.provider('greet', GreetProvider); - * }); + * })); * * it('should greet', inject(function(greet) { * expect(greet('angular')).toEqual('Hello angular!'); @@ -2559,9 +2613,7 @@ function annotate(fn) { * inject(function(greet) { * expect(greet('angular')).toEqual('Ahoj angular!'); * }); - * )}; - * - * }); + * }); *
*/ @@ -2655,7 +2707,7 @@ function annotate(fn) { * * @param {string} name The name of the service to decorate. * @param {function()} decorator This function will be invoked when the service needs to be - * instanciated. The function is called using the {@link AUTO.$injector#invoke + * instantiated. The function is called using the {@link AUTO.$injector#invoke * injector.invoke} method and is therefore fully injectable. Local injection arguments: * * * `$delegate` - The original service instance, which can be monkey patched, configured, @@ -2855,6 +2907,8 @@ function createInjector(modulesToLoad) { var Constructor = function() {}, instance, returnedValue; + // Check if Type is annotated and use just the given function at n-1 as parameter + // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]); Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype; instance = new Constructor(); returnedValue = invoke(Type, instance, locals); @@ -2870,6 +2924,7 @@ function createInjector(modulesToLoad) { }; } } + /** * @ngdoc function * @name ng.$anchorScroll @@ -3234,7 +3289,13 @@ function Browser(window, document, $log, $sniffer) { cookie = cookieArray[i]; index = cookie.indexOf('='); if (index > 0) { //ignore nameless cookies - lastCookies[unescape(cookie.substring(0, index))] = unescape(cookie.substring(index + 1)); + var name = unescape(cookie.substring(0, index)); + // the first value that is seen for a cookie is the most + // specific one. values for the same cookie name that + // follow are for less specific paths. + if (lastCookies[name] === undefined) { + lastCookies[name] = unescape(cookie.substring(index + 1)); + } } } } @@ -3298,6 +3359,7 @@ function $BrowserProvider(){ return new Browser($window, $document, $log, $sniffer); }]; } + /** * @ngdoc object * @name ng.$cacheFactory @@ -3625,7 +3687,7 @@ function $CompileProvider($provide) { COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/, CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/, MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ', - urlSanitizationWhitelist = /^\s*(https?|ftp|mailto):/; + urlSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/; /** @@ -3827,7 +3889,7 @@ function $CompileProvider($provide) { function compile($compileNodes, transcludeFn, maxPriority) { if (!($compileNodes instanceof jqLite)) { - // jquery always rewraps, where as we need to preserve the original selector so that we can modify it. + // jquery always rewraps, whereas we need to preserve the original selector so that we can modify it. $compileNodes = jqLite($compileNodes); } // We can not compile top level text elements since text nodes can be merged and we will @@ -3879,7 +3941,7 @@ function $CompileProvider($provide) { * functions return values - the linking functions - are combined into a composite linking * function, which is the a linking function for the node. * - * @param {NodeList} nodeList an array of nodes to compile + * @param {NodeList} nodeList an array of nodes or NodeList to compile * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the * scope argument is auto-generated to the new child of the transcluded parent scope. * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then the @@ -3902,7 +3964,7 @@ function $CompileProvider($provide) { ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement) : null; - childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes.length) + childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes || !nodeList[i].childNodes.length) ? null : compileNodes(nodeList[i].childNodes, nodeLinkFn ? nodeLinkFn.transclude : transcludeFn); @@ -4038,9 +4100,9 @@ function $CompileProvider($provide) { /** - * Once the directives have been collected their compile functions is executed. This method + * Once the directives have been collected, their compile functions are executed. This method * is responsible for inlining directive templates as well as terminating the application - * of the directives if the terminal directive has been reached.. + * of the directives if the terminal directive has been reached. * * @param {Array} directives Array of collected directives to execute their compile function. * this needs to be pre-sorted by priority order. @@ -4048,11 +4110,11 @@ function $CompileProvider($provide) { * @param {Object} templateAttrs The shared attribute function * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the * scope argument is auto-generated to the new child of the transcluded parent scope. - * @param {DOMElement} $rootElement If we are working on the root of the compile tree then this - * argument has the root jqLite array so that we can replace widgets on it. + * @param {JQLite} jqCollection If we are working on the root of the compile tree then this + * argument has the root jqLite array so that we can replace nodes on it. * @returns linkFn */ - function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, $rootElement) { + function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection) { var terminalPriority = -Number.MAX_VALUE, preLinkFns = [], postLinkFns = [], @@ -4106,7 +4168,7 @@ function $CompileProvider($provide) { $compileNode = templateAttrs.$$element = jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' ')); compileNode = $compileNode[0]; - replaceWith($rootElement, jqLite($template[0]), compileNode); + replaceWith(jqCollection, jqLite($template[0]), compileNode); childTranscludeFn = compile($template, transcludeFn, terminalPriority); } else { $template = jqLite(JQLiteClone(compileNode)).contents(); @@ -4130,7 +4192,7 @@ function $CompileProvider($provide) { throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue); } - replaceWith($rootElement, $compileNode, compileNode); + replaceWith(jqCollection, $compileNode, compileNode); var newTemplateAttrs = {$attr: {}}; @@ -4158,7 +4220,7 @@ function $CompileProvider($provide) { assertNoDuplicate('template', templateDirective, directive, $compileNode); templateDirective = directive; nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), - nodeLinkFn, $compileNode, templateAttrs, $rootElement, directive.replace, + nodeLinkFn, $compileNode, templateAttrs, jqCollection, directive.replace, childTranscludeFn); ii = directives.length; } else if (directive.compile) { @@ -4291,7 +4353,7 @@ function $CompileProvider($provide) { parentGet = $parse(attrs[attrName]); scope[scopeName] = function(locals) { return parentGet(parentScope, locals); - } + }; break; } @@ -4461,7 +4523,7 @@ function $CompileProvider($provide) { directives.unshift(derivedSyncDirective); afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn); - afterTemplateChildLinkFn = compileNodes($compileNode.contents(), childTranscludeFn); + afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn); while(linkQueue.length) { @@ -4726,7 +4788,7 @@ function $ControllerProvider() { * @description * `$controller` service is responsible for instantiating controllers. * - * It's just simple call to {@link AUTO.$injector $injector}, but extracted into + * It's just a simple call to {@link AUTO.$injector $injector}, but extracted into * a service, so that one can override this service with {@link https://gist.github.com/1649788 * BC version}. */ @@ -4779,7 +4841,7 @@ function $DocumentProvider(){ * */ function $ExceptionHandlerProvider() { - this.$get = ['$log', function($log){ + this.$get = ['$log', function($log) { return function(exception, cause) { $log.error.apply($log, arguments); }; @@ -4967,7 +5029,7 @@ function $InterpolateProvider() { }]; } -var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/, +var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/, PATH_MATCH = /^([^\?#]*)?(\?([^#]*))?(#(.*))?$/, HASH_MATCH = PATH_MATCH, DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21}; @@ -5046,7 +5108,8 @@ function convertToHashbangUrl(url, basePath, hashPrefix) { var match = matchUrl(url); // already hashbang url - if (decodeURIComponent(match.path) == basePath) { + if (decodeURIComponent(match.path) == basePath && !isUndefined(match.hash) && + match.hash.indexOf(hashPrefix) === 0) { return url; // convert html5 url -> hashbang url } else { @@ -5543,6 +5606,10 @@ function $LocationProvider(){ // update $location when $browser url changes $browser.onUrlChange(function(newUrl) { if ($location.absUrl() != newUrl) { + if ($rootScope.$broadcast('$locationChangeStart', newUrl, $location.absUrl()).defaultPrevented) { + $browser.url($location.absUrl()); + return; + } $rootScope.$evalAsync(function() { var oldUrl = $location.absUrl(); @@ -5851,10 +5918,10 @@ function lex(text, csp){ function readIdent() { var ident = "", start = index, - lastDot, peekIndex, methodName; + lastDot, peekIndex, methodName, ch; while (index < text.length) { - var ch = text.charAt(index); + ch = text.charAt(index); if (ch == '.' || isIdent(ch) || isNumber(ch)) { if (ch == '.') lastDot = index; ident += ch; @@ -5868,7 +5935,7 @@ function lex(text, csp){ if (lastDot) { peekIndex = index; while(peekIndex < text.length) { - var ch = text.charAt(peekIndex); + ch = text.charAt(peekIndex); if (ch == '(') { methodName = ident.substr(lastDot - start + 1); ident = ident.substr(0, lastDot - start); @@ -6121,8 +6188,8 @@ function parser(text, json, $filter, csp){ text.substring(0, token.index) + "] can not be assigned to", token); } right = logicalOR(); - return function(self, locals){ - return left.assign(self, right(self, locals), locals); + return function(scope, locals){ + return left.assign(scope, right(scope, locals), locals); }; } else { return left; @@ -6239,12 +6306,12 @@ function parser(text, json, $filter, csp){ var field = expect().text; var getter = getterFn(field, csp); return extend( - function(self, locals) { - return getter(object(self, locals), locals); + function(scope, locals, self) { + return getter(self || object(scope, locals), locals); }, { - assign:function(self, value, locals) { - return setter(object(self, locals), field, value); + assign:function(scope, value, locals) { + return setter(object(scope, locals), field, value); } } ); @@ -6285,14 +6352,14 @@ function parser(text, json, $filter, csp){ } while (expect(',')); } consume(')'); - return function(self, locals){ + return function(scope, locals){ var args = [], - context = contextGetter ? contextGetter(self, locals) : self; + context = contextGetter ? contextGetter(scope, locals) : scope; for ( var i = 0; i < argsFn.length; i++) { - args.push(argsFn[i](self, locals)); + args.push(argsFn[i](scope, locals)); } - var fnPtr = fn(self, locals) || noop; + var fnPtr = fn(scope, locals, context) || noop; // IE stupidity! return fnPtr.apply ? fnPtr.apply(context, args) @@ -6334,8 +6401,7 @@ function parser(text, json, $filter, csp){ var object = {}; for ( var i = 0; i < keyValues.length; i++) { var keyValue = keyValues[i]; - var value = keyValue.value(self, locals); - object[keyValue.key] = value; + object[keyValue.key] = keyValue.value(self, locals); } return object; }; @@ -6457,7 +6523,7 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4) { } return pathVal; }; -}; +} function getterFn(path, csp) { if (getterFnCache.hasOwnProperty(path)) { @@ -6472,7 +6538,7 @@ function getterFn(path, csp) { fn = (pathKeysLength < 6) ? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4]) : function(scope, locals) { - var i = 0, val + var i = 0, val; do { val = cspSafeGetterFn( pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++] @@ -6685,7 +6751,7 @@ function $ParseProvider() { * models and avoiding unnecessary browser repaints, which would result in flickering UI. * - $q promises are recognized by the templating engine in angular, which means that in templates * you can treat promises attached to a scope as if they were the resulting values. - * - Q has many more features that $q, but that comes at a cost of bytes. $q is tiny, but contains + * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains * all the important functionality needed for common async tasks. * * # Testing @@ -6880,10 +6946,7 @@ function qFactory(nextTick, exceptionHandler) { * the promise comes from a source that can't be trusted. * * @param {*} value Value or a promise - * @returns {Promise} Returns a single promise that will be resolved with an array of values, - * each value corresponding to the promise at the same index in the `promises` array. If any of - * the promises is resolved with a rejection, this resulting promise will be resolved with the - * same rejection. + * @returns {Promise} Returns a promise of the passed value or promise */ var when = function(value, callback, errback) { var result = defer(), @@ -7240,8 +7303,9 @@ function $RouteProvider(){ * {@link ng.directive:ngView ngView} listens for the directive * to instantiate the controller and render the view. * + * @param {Object} angularEvent Synthetic event object. * @param {Route} current Current route information. - * @param {Route} previous Previous route information. + * @param {Route|Undefined} previous Previous route information, or undefined if current is first route entered. */ /** @@ -7339,7 +7403,7 @@ function $RouteProvider(){ var next = parseRoute(), last = $route.current; - if (next && last && next.$route === last.$route + if (next && last && next.$$route === last.$$route && equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) { last.params = next.params; copy(last.params, $routeParams); @@ -7418,7 +7482,7 @@ function $RouteProvider(){ match = inherit(route, { params: extend({}, $location.search(), params), pathParams: params}); - match.$route = route; + match.$$route = route; } }); // No route matched; fallback to "otherwise" route @@ -7478,22 +7542,22 @@ function $RouteParamsProvider() { /** * DESIGN NOTES * - * The design decisions behind the scope ware heavily favored for speed and memory consumption. + * The design decisions behind the scope are heavily favored for speed and memory consumption. * * The typical use of scope is to watch the expressions, which most of the time return the same * value as last time so we optimize the operation. * - * Closures construction is expensive from speed as well as memory: - * - no closures, instead ups prototypical inheritance for API + * Closures construction is expensive in terms of speed as well as memory: + * - No closures, instead use prototypical inheritance for API * - Internal state needs to be stored on scope directly, which means that private state is * exposed as $$____ properties * * Loop operations are optimized by using while(count--) { ... } * - this means that in order to keep the same order of execution as addition we have to add - * items to the array at the begging (shift) instead of at the end (push) + * items to the array at the beginning (shift) instead of at the end (push) * * Child scopes are created and removed often - * - Using array would be slow since inserts in meddle are expensive so we use linked list + * - Using an array would be slow since inserts in middle are expensive so we use linked list * * There are few watches then a lot of observers. This is why you don't want the observer to be * implemented in the same way as watch. Watch requires return of initialization function which @@ -7515,7 +7579,7 @@ function $RouteParamsProvider() { * @methodOf ng.$rootScopeProvider * @description * - * Sets the number of digest iteration the scope should attempt to execute before giving up and + * Sets the number of digest iterations the scope should attempt to execute before giving up and * assuming that the model is unstable. * * The current default is 10 iterations. @@ -7795,7 +7859,7 @@ function $RootScopeProvider(){ * @function * * @description - * Process all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children. + * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children. * Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the * `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} until no more listeners are * firing. This means that it is possible to get into an infinite loop. This function will throw @@ -8137,7 +8201,7 @@ function $RootScopeProvider(){ * Afterwards, the event traverses upwards toward the root scope and calls all registered * listeners along the way. The event will stop propagating if one of the listeners cancels it. * - * Any exception emmited from the {@link ng.$rootScope.Scope#$on listeners} will be passed + * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed * onto the {@link ng.$exceptionHandler $exceptionHandler} service. * * @param {string} name Event name to emit. @@ -8206,7 +8270,7 @@ function $RootScopeProvider(){ * Any exception emmited from the {@link ng.$rootScope.Scope#$on listeners} will be passed * onto the {@link ng.$exceptionHandler $exceptionHandler} service. * - * @param {string} name Event name to emit. + * @param {string} name Event name to broadcast. * @param {...*} args Optional set of arguments which will be passed onto the event listeners. * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on} */ @@ -8352,10 +8416,23 @@ function $SnifferProvider() { * @example - - + +
+ + +
+ it('should display the greeting in the input box', function() { + input('greeting').enter('Hello, E2E Tests'); + // If we click the button it will block the test runner + // element(':button').click(); + });
*/ @@ -8508,7 +8585,7 @@ function $HttpProvider() { * * @description * The `$http` service is a core Angular service that facilitates communication with the remote - * HTTP servers via browser's {@link https://developer.mozilla.org/en/xmlhttprequest + * HTTP servers via the browser's {@link https://developer.mozilla.org/en/xmlhttprequest * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}. * * For unit testing applications that use `$http` service, see @@ -8518,13 +8595,13 @@ function $HttpProvider() { * $resource} service. * * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by - * the $q service. While for simple usage patters this doesn't matter much, for advanced usage, - * it is important to familiarize yourself with these apis and guarantees they provide. + * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage + * it is important to familiarize yourself with these APIs and the guarantees they provide. * * * # General usage * The `$http` service is a function which takes a single argument — a configuration object — - * that is used to generate an http request and returns a {@link ng.$q promise} + * that is used to generate an HTTP request and returns a {@link ng.$q promise} * with two $http specific methods: `success` and `error`. * *
@@ -8539,21 +8616,21 @@ function $HttpProvider() {
      *     });
      * 
* - * Since the returned value of calling the $http function is a Promise object, you can also use + * Since the returned value of calling the $http function is a `promise`, you can also use * the `then` method to register callbacks, and these callbacks will receive a single argument – - * an object representing the response. See the api signature and type info below for more + * an object representing the response. See the API signature and type info below for more * details. * - * A response status code that falls in the [200, 300) range is considered a success status and + * A response status code between 200 and 299 is considered a success status and * will result in the success callback being called. Note that if the response is a redirect, * XMLHttpRequest will transparently follow it, meaning that the error callback will not be * called for such responses. * * # Shortcut methods * - * Since all invocation of the $http service require definition of the http method and url and - * POST and PUT requests require response body/data to be provided as well, shortcut methods - * were created to simplify using the api: + * Since all invocations of the $http service require passing in an HTTP method and URL, and + * POST/PUT requests require request data to be provided as well, shortcut methods + * were created: * *
      *   $http.get('/someUrl').success(successCallback);
@@ -8572,25 +8649,25 @@ function $HttpProvider() {
      *
      * # Setting HTTP Headers
      *
-     * The $http service will automatically add certain http headers to all requests. These defaults
+     * The $http service will automatically add certain HTTP headers to all requests. These defaults
      * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
      * object, which currently contains this default configuration:
      *
      * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
      *   - `Accept: application/json, text/plain, * / *`
      *   - `X-Requested-With: XMLHttpRequest`
-     * - `$httpProvider.defaults.headers.post`: (header defaults for HTTP POST requests)
+     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
      *   - `Content-Type: application/json`
-     * - `$httpProvider.defaults.headers.put` (header defaults for HTTP PUT requests)
+     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
      *   - `Content-Type: application/json`
      *
-     * To add or overwrite these defaults, simply add or remove a property from this configuration
+     * To add or overwrite these defaults, simply add or remove a property from these configuration
      * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
-     * with name equal to the lower-cased http method name, e.g.
+     * with the lowercased HTTP method name as the key, e.g.
      * `$httpProvider.defaults.headers.get['My-Header']='value'`.
      *
-     * Additionally, the defaults can be set at runtime via the `$http.defaults` object in a similar
-     * fassion as described above.
+     * Additionally, the defaults can be set at runtime via the `$http.defaults` object in the same
+     * fashion.
      *
      *
      * # Transforming Requests and Responses
@@ -8600,32 +8677,36 @@ function $HttpProvider() {
      *
      * Request transformations:
      *
-     * - if the `data` property of the request config object contains an object, serialize it into
+     * - If the `data` property of the request configuration object contains an object, serialize it into
      *   JSON format.
      *
      * Response transformations:
      *
-     *  - if XSRF prefix is detected, strip it (see Security Considerations section below)
-     *  - if json response is detected, deserialize it using a JSON parser
+     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
+     *  - If JSON response is detected, deserialize it using a JSON parser.
+     *
+     * To globally augment or override the default transforms, modify the `$httpProvider.defaults.transformRequest` and
+     * `$httpProvider.defaults.transformResponse` properties. These properties are by default an
+     * array of transform functions, which allows you to `push` or `unshift` a new transformation function into the
+     * transformation chain. You can also decide to completely override any default transformations by assigning your
+     * transformation functions to these properties directly without the array wrapper.
      *
-     * To override these transformation locally, specify transform functions as `transformRequest`
-     * and/or `transformResponse` properties of the config object. To globally override the default
-     * transforms, override the `$httpProvider.defaults.transformRequest` and
-     * `$httpProvider.defaults.transformResponse` properties of the `$httpProvider`.
+     * Similarly, to locally override the request/response transforms, augment the `transformRequest` and/or
+     * `transformResponse` properties of the configuration object passed into `$http`.
      *
      *
      * # Caching
      *
-     * To enable caching set the configuration property `cache` to `true`. When the cache is
+     * To enable caching, set the configuration property `cache` to `true`. When the cache is
      * enabled, `$http` stores the response from the server in local cache. Next time the
      * response is served from the cache without sending a request to the server.
      *
      * Note that even if the response is served from cache, delivery of the data is asynchronous in
      * the same way that real requests are.
      *
-     * If there are multiple GET requests for the same url that should be cached using the same
+     * If there are multiple GET requests for the same URL that should be cached using the same
      * cache, but the cache is not populated yet, only one request to the server will be made and
-     * the remaining requests will be fulfilled using the response for the first request.
+     * the remaining requests will be fulfilled using the response from the first request.
      *
      *
      * # Response interceptors
@@ -8677,7 +8758,7 @@ function $HttpProvider() {
      * When designing web applications, consider security threats from:
      *
      * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
-     *   JSON Vulnerability}
+     *   JSON vulnerability}
      * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
      *
      * Both server and the client must cooperate in order to eliminate these threats. Angular comes
@@ -8687,8 +8768,8 @@ function $HttpProvider() {
      * ## JSON Vulnerability Protection
      *
      * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
-     * JSON Vulnerability} allows third party web-site to turn your JSON resource URL into
-     * {@link http://en.wikipedia.org/wiki/JSON#JSONP JSONP} request under some conditions. To
+     * JSON vulnerability} allows third party website to turn your JSON resource URL into
+     * {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To
      * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
      * Angular will automatically strip the prefix before processing it as JSON.
      *
@@ -8709,19 +8790,19 @@ function $HttpProvider() {
      * ## Cross Site Request Forgery (XSRF) Protection
      *
      * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
-     * an unauthorized site can gain your user's private data. Angular provides following mechanism
+     * an unauthorized site can gain your user's private data. Angular provides a mechanism
      * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
      * called `XSRF-TOKEN` and sets it as the HTTP header `X-XSRF-TOKEN`. Since only JavaScript that
      * runs on your domain could read the cookie, your server can be assured that the XHR came from
      * JavaScript running on your domain.
      *
      * To take advantage of this, your server needs to set a token in a JavaScript readable session
-     * cookie called `XSRF-TOKEN` on first HTTP GET request. On subsequent non-GET requests the
+     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
      * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
-     * that only JavaScript running on your domain could have read the token. The token must be
-     * unique for each user and must be verifiable by the server (to prevent the JavaScript making
+     * that only JavaScript running on your domain could have sent the request. The token must be
+     * unique for each user and must be verifiable by the server (to prevent the JavaScript from making
      * up its own tokens). We recommend that the token is a digest of your site's authentication
-     * cookie with {@link http://en.wikipedia.org/wiki/Rainbow_table salt for added security}.
+     * cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} for added security.
      *
      *
      * @param {object} config Object describing the request to be made and how it should be
@@ -8899,7 +8980,7 @@ function $HttpProvider() {
      * @methodOf ng.$http
      *
      * @description
-     * Shortcut method to perform `GET` request
+     * Shortcut method to perform `GET` request.
      *
      * @param {string} url Relative or absolute URL specifying the destination of the request
      * @param {Object=} config Optional configuration object
@@ -8912,7 +8993,7 @@ function $HttpProvider() {
      * @methodOf ng.$http
      *
      * @description
-     * Shortcut method to perform `DELETE` request
+     * Shortcut method to perform `DELETE` request.
      *
      * @param {string} url Relative or absolute URL specifying the destination of the request
      * @param {Object=} config Optional configuration object
@@ -8925,7 +9006,7 @@ function $HttpProvider() {
      * @methodOf ng.$http
      *
      * @description
-     * Shortcut method to perform `HEAD` request
+     * Shortcut method to perform `HEAD` request.
      *
      * @param {string} url Relative or absolute URL specifying the destination of the request
      * @param {Object=} config Optional configuration object
@@ -8938,7 +9019,7 @@ function $HttpProvider() {
      * @methodOf ng.$http
      *
      * @description
-     * Shortcut method to perform `JSONP` request
+     * Shortcut method to perform `JSONP` request.
      *
      * @param {string} url Relative or absolute URL specifying the destination of the request.
      *                     Should contain `JSON_CALLBACK` string.
@@ -8953,7 +9034,7 @@ function $HttpProvider() {
      * @methodOf ng.$http
      *
      * @description
-     * Shortcut method to perform `POST` request
+     * Shortcut method to perform `POST` request.
      *
      * @param {string} url Relative or absolute URL specifying the destination of the request
      * @param {*} data Request content
@@ -8967,7 +9048,7 @@ function $HttpProvider() {
      * @methodOf ng.$http
      *
      * @description
-     * Shortcut method to perform `PUT` request
+     * Shortcut method to perform `PUT` request.
      *
      * @param {string} url Relative or absolute URL specifying the destination of the request
      * @param {*} data Request content
@@ -9019,7 +9100,7 @@ function $HttpProvider() {
 
 
     /**
-     * Makes the request
+     * Makes the request.
      *
      * !!! ACCESSES CLOSURE VARS:
      * $httpBackend, $config, $log, $rootScope, defaultCache, $http.pendingRequests
@@ -9129,6 +9210,7 @@ function $HttpProvider() {
 
   }];
 }
+
 var XHR = window.XMLHttpRequest || function() {
   try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
   try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
@@ -9365,17 +9447,17 @@ function $TimeoutProvider() {
       * block and delegates any exceptions to
       * {@link ng.$exceptionHandler $exceptionHandler} service.
       *
-      * The return value of registering a timeout function is a promise which will be resolved when
+      * The return value of registering a timeout function is a promise, which will be resolved when
       * the timeout is reached and the timeout function is executed.
       *
-      * To cancel a the timeout request, call `$timeout.cancel(promise)`.
+      * To cancel a timeout request, call `$timeout.cancel(promise)`.
       *
       * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
       * synchronously flush the queue of deferred functions.
       *
-      * @param {function()} fn A function, who's execution should be delayed.
+      * @param {function()} fn A function, whose execution should be delayed.
       * @param {number=} [delay=0] Delay in milliseconds.
-      * @param {boolean=} [invokeApply=true] If set to false skips model dirty checking, otherwise
+      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
       * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
       *   promise will be resolved with is the return value of the `fn` function.
@@ -9415,7 +9497,7 @@ function $TimeoutProvider() {
       * @methodOf ng.$timeout
       *
       * @description
-      * Cancels a task associated with the `promise`. As a result of this the promise will be
+      * Cancels a task associated with the `promise`. As a result of this, the promise will be
       * resolved with a rejection.
       *
       * @param {Promise=} promise Promise returned by the `$timeout` function.
@@ -9441,7 +9523,7 @@ function $TimeoutProvider() {
  *
  * Filters are just functions which transform input to an output. However filters need to be Dependency Injected. To
  * achieve this a filter definition consists of a factory function which is annotated with dependencies and is
- * responsible for creating a the filter function.
+ * responsible for creating a filter function.
  *
  * 
  *   // Filter registration
@@ -9503,7 +9585,7 @@ function $TimeoutProvider() {
  *
  * The general syntax in templates is as follows:
  *
- *         {{ expression | [ filter_name ] }}
+ *         {{ expression [| filter_name[:parameter_value] ... ] }}
  *
  * @param {String} name Name of the filter function to retrieve
  * @return {Function} the filter function
@@ -9579,22 +9661,22 @@ function $FilterProvider($provide) {
 
        Search: 
        
-         
+         
-         
+         
NamePhone
NamePhone
{{friend.name}} {{friend.phone}}

Any:
Name only
- Phone only
+ Phone only
- + - +
NamePhone
NamePhone
{{friend.name}} {{friend.phone}}
@@ -9891,6 +9973,7 @@ function padNumber(num, digits, trim) { function dateGetter(name, size, offset, trim) { + offset = offset || 0; return function(date) { var value = date['get' + name](); if (offset > 0 || value > -offset) @@ -9913,7 +9996,8 @@ function timeZoneGetter(date) { var zone = -1 * date.getTimezoneOffset(); var paddedZone = (zone >= 0) ? "+" : ""; - paddedZone += padNumber(zone / 60, 2) + padNumber(Math.abs(zone % 60), 2); + paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) + + padNumber(Math.abs(zone % 60), 2); return paddedZone; } @@ -9979,7 +10063,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+ * * `'ss'`: Second in minute, padded (00-59) * * `'s'`: Second in minute (0-59) * * `'a'`: am/pm marker - * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-1200) + * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200) * * `format` string can also be one of the following predefined * {@link guide/i18n localizable formats}: @@ -10000,7 +10084,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+ * (e.g. `"h o''clock"`). * * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or - * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and it's + * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is * specified in the string input, the time is considered to be in the local timezone. * @param {string=} format Formatting rules (see Description). If not specified, @@ -10291,12 +10375,12 @@ function limitToFilter(){ (^) Phone Number Age - + {{friend.name}} {{friend.phone}} {{friend.age}} - + @@ -11118,8 +11202,8 @@ var inputType = { * * @param {string} ngModel Assignable angular expression to data-bind to. * @param {string=} name Property name of the form under which the control is published. - * @param {string=} min Sets the `min` validation error key if the value entered is less then `min`. - * @param {string=} max Sets the `max` validation error key if the value entered is greater then `min`. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. * @param {string=} required Sets `required` validation error key if the value is not entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of @@ -11431,6 +11515,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { } else { var timeout; + var deferListener = function() { + if (!timeout) { + timeout = $browser.defer(function() { + listener(); + timeout = null; + }); + } + }; + element.bind('keydown', function(event) { var key = event.keyCode; @@ -11438,16 +11531,16 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { // command modifiers arrows if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return; - if (!timeout) { - timeout = $browser.defer(function() { - listener(); - timeout = null; - }); - } + deferListener(); }); // if user paste into input using mouse, we need "change" event to catch it element.bind('change', listener); + + // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it + if ($sniffer.hasEvent('paste')) { + element.bind('paste cut', deferListener); + } } @@ -11746,7 +11839,7 @@ function checkboxInputType(scope, element, attr, ctrl) { myForm.userName.$valid = {{myForm.userName.$valid}}
myForm.userName.$error = {{myForm.userName.$error}}
myForm.lastName.$valid = {{myForm.lastName.$valid}}
- myForm.userName.$error = {{myForm.lastName.$error}}
+ myForm.lastName.$error = {{myForm.lastName.$error}}
myForm.$valid = {{myForm.$valid}}
myForm.$error.required = {{!!myForm.$error.required}}
myForm.$error.minlength = {{!!myForm.$error.minlength}}
@@ -12009,7 +12102,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ * For example {@link ng.directive:input input} or * {@link ng.directive:select select} directives call it. * - * It internally calls all `formatters` and if resulted value is valid, updates the model and + * It internally calls all `parsers` and if resulted value is valid, updates the model and * calls all registered change listeners. * * @param {string} value Value from the view. @@ -12315,7 +12408,7 @@ var ngValueDirective = function() { * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like * `{{ expression }}` which is similar but less verbose. * - * Once scenario in which the use of `ngBind` is prefered over `{{ expression }}` binding is when + * One scenario in which the use of `ngBind` is preferred over `{{ expression }}` binding is when * it's desirable to put bindings into template that is momentarily displayed by the browser in its * raw state before Angular compiles it. Since `ngBind` is an element attribute, it makes the * bindings invisible to the user while the page is loading. @@ -12456,9 +12549,9 @@ function classDirective(name, selector) { if (name !== 'ngClass') { scope.$watch('$index', function($index, old$index) { - var mod = $index % 2; - if (mod !== old$index % 2) { - if (mod == selector) { + var mod = $index & 1; + if (mod !== old$index & 1) { + if (mod === selector) { addClass(scope.$eval(attr[name])); } else { removeClass(scope.$eval(attr[name])); @@ -12470,12 +12563,12 @@ function classDirective(name, selector) { function ngClassWatchAction(newVal) { if (selector === true || scope.$index % 2 === selector) { - if (oldVal && (newVal !== oldVal)) { + if (oldVal && !equals(newVal,oldVal)) { removeClass(oldVal); } addClass(newVal); } - oldVal = newVal; + oldVal = copy(newVal); } @@ -12601,7 +12694,7 @@ var ngClassOddDirective = classDirective('Odd', 0); * @name ng.directive:ngClassEven * * @description - * The `ngClassOdd` and `ngClassEven` works exactly as + * The `ngClassOdd` and `ngClassEven` directives work exactly as * {@link ng.directive:ngClass ngClass}, except it works in * conjunction with `ngRepeat` and takes affect only on odd (even) rows. * @@ -12659,7 +12752,7 @@ var ngClassEvenDirective = classDirective('Even', 1); * `angular.min.js` files. Following is the css rule: * *
- * [ng\:cloak], [ng-cloak], .ng-cloak {
+ * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
  *   display: none;
  * }
  * 
@@ -12718,8 +12811,7 @@ var ngCloakDirective = ngDirective({ * * Controller — The `ngController` directive specifies a Controller class; the class has * methods that typically express the business logic behind the application. * - * Note that an alternative way to define controllers is via the `{@link ng.$route}` - * service. + * Note that an alternative way to define controllers is via the {@link ng.$route $route} service. * * @element ANY * @scope @@ -12810,16 +12902,32 @@ var ngControllerDirective = [function() { * @name ng.directive:ngCsp * @priority 1000 * + * @element html * @description * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support. - * This directive should be used on the root element of the application (typically the `` - * element or other element with the {@link ng.directive:ngApp ngApp} - * directive). - * - * If enabled the performance of template expression evaluator will suffer slightly, so don't enable - * this mode unless you need it. - * - * @element html + * + * This is necessary when developing things like Google Chrome Extensions. + * + * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things). + * For us to be compatible, we just need to implement the "getterFn" in $parse without violating + * any of these restrictions. + * + * AngularJS uses `Function(string)` generated functions as a speed optimization. By applying `ngCsp` + * it is be possible to opt into the CSP compatible mode. When this mode is on AngularJS will + * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will + * be raised. + * + * In order to use this feature put `ngCsp` directive on the root element of the application. + * + * @example + * This example shows how to apply the `ngCsp` directive to the `html` tag. +
+     
+     
+     ...
+     ...
+     
+   
*/ var ngCspDirective = ['$sniffer', function($sniffer) { @@ -13444,7 +13552,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp if (!isNaN(value)) { //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise, //check it against pluralization rules in $locale service - if (!whens[value]) value = $locale.pluralCat(value - offset); + if (!(value in whens)) value = $locale.pluralCat(value - offset); return whensExpFns[value](scope, element, true); } else { return ''; @@ -13552,7 +13660,7 @@ var ngRepeatDirective = ngDirective({ // Same as lastOrder but it has the current state. It will become the // lastOrder on the next iteration. nextOrder = new HashQueueMap(), - arrayLength, + arrayBound, childScope, key, value, // key/value of iteration array, @@ -13573,7 +13681,7 @@ var ngRepeatDirective = ngDirective({ array = collection || []; } - arrayLength = array.length; + arrayBound = array.length-1; // we are not using forEach for perf reasons (trying to avoid #call) for (index = 0, length = array.length; index < length; index++) { @@ -13610,7 +13718,7 @@ var ngRepeatDirective = ngDirective({ childScope.$index = index; childScope.$first = (index === 0); - childScope.$last = (index === (arrayLength - 1)); + childScope.$last = (index === arrayBound); childScope.$middle = !(childScope.$first || childScope.$last); if (!last) { @@ -13777,11 +13885,13 @@ var ngStyleDirective = ngDirective(function(scope, element, attr) { * @description * Conditionally change the DOM structure. * - * @usageContent - * ... + * @usage + * + * ... * ... * ... * ... + * * * @scope * @param {*} ngSwitch|on expression to match against ng-switch-when. @@ -14175,7 +14285,8 @@ var scriptDirective = ['$templateCache', function($templateCache) { * `select` model to be bound to a non-string value. This is because an option element can currently * be bound to string values only. * - * @param {string} name assignable expression to data-bind to. + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. * @param {string=} required The control is considered valid only if value is entered. * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of @@ -14270,7 +14381,7 @@ var scriptDirective = ['$templateCache', function($templateCache) { var ngOptionsDirective = valueFn({ terminal: true }); var selectDirective = ['$compile', '$parse', function($compile, $parse) { - //00001111100000000000222200000000000000000000003333000000000000044444444444444444000000000555555555555555550000000666666666666666660000000000000007777 + //0000111110000000000022220000000000000000000000333300000000000000444444444444444440000000005555555555555555500000006666666666666666600000000000000077770 var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/, nullModelCtrl = {$setViewValue: noop}; @@ -14542,10 +14653,6 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { if (multiple) { selectedSet = new HashMap(modelValue); - } else if (modelValue === null || nullOption) { - // if we are not multiselect, and we are null then we have to add the nullOption - optionGroups[''].push({selected:modelValue === null, id:'', label:''}); - selectedSet = true; } // We now build up the list of options we need (we merge later) @@ -14570,9 +14677,14 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { selected: selected // determine if we should be selected }); } - if (!multiple && !selectedSet) { - // nothing was selected, we have to insert the undefined item - optionGroups[''].unshift({id:'?', label:'', selected:true}); + if (!multiple) { + if (nullOption || modelValue === null) { + // insert null option if we have a placeholder, or the model is null + optionGroups[''].unshift({id:'', label:'', selected:!selectedSet}); + } else if (!selectedSet) { + // option could not be found, we have to insert the undefined item + optionGroups[''].unshift({id:'?', label:'', selected:true}); + } } // Now we need to update the list of DOM nodes to match the optionGroups we computed above @@ -14616,7 +14728,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { if (existingOption.id !== option.id) { lastElement.val(existingOption.id = option.id); } - if (existingOption.element.selected !== option.selected) { + // lastElement.prop('selected') provided by jQuery has side-effects + if (lastElement[0].selected !== option.selected) { lastElement.prop('selected', (existingOption.selected = option.selected)); } } else { @@ -14719,6 +14832,7 @@ var styleDirective = valueFn({ restrict: 'E', terminal: true }); + //try to bind to jquery now so that one can write angular.element().read() //but we will rebind on bootstrap again. bindJQuery(); diff --git a/architecture-examples/angularjs/bower_components/todomvc-common/base.css b/architecture-examples/angularjs/bower_components/todomvc-common/base.css index 8d1db3a696..3e6bfaf38d 100644 --- a/architecture-examples/angularjs/bower_components/todomvc-common/base.css +++ b/architecture-examples/angularjs/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -412,3 +412,144 @@ label[for='toggle-all'] { .hidden{ display:none; } + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/architecture-examples/angularjs/bower_components/todomvc-common/base.js b/architecture-examples/angularjs/bower_components/todomvc-common/base.js index 3fd166d061..099da60dd1 100644 --- a/architecture-examples/angularjs/bower_components/todomvc-common/base.js +++ b/architecture-examples/angularjs/bower_components/todomvc-common/base.js @@ -1,38 +1,209 @@ (function () { 'use strict'; + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + if (location.hostname === 'todomvc.com') { window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); } - function getSourcePath() { - // If accessed via addyosmani.github.io/todomvc/, strip the project path. - if (location.hostname.indexOf('github.io') > 0) { - return location.pathname.replace(/todomvc\//, ''); + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); } - return location.pathname; } - function appendSourceLink() { - var sourceLink = document.createElement('a'); - var paragraph = document.createElement('p'); - var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } - if (footer) { - sourceLink.href = urlBase + getSourcePath(); - sourceLink.appendChild(document.createTextNode('Check out the source')); - paragraph.appendChild(sourceLink); - footer.appendChild(paragraph); + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; } - function redirect() { - if (location.hostname === 'addyosmani.github.io') { - location.href = location.href.replace('addyosmani.github.io/todomvc', 'todomvc.com'); + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); } } - appendSourceLink(); + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + redirect(); + getFile('learn.json', Learn); })(); diff --git a/architecture-examples/angularjs/index.html b/architecture-examples/angularjs/index.html index 682be02150..058f5a61eb 100644 --- a/architecture-examples/angularjs/index.html +++ b/architecture-examples/angularjs/index.html @@ -1,11 +1,11 @@ - + - + AngularJS • TodoMVC - +
@@ -26,7 +26,7 @@

todos

- +
@@ -66,5 +66,6 @@

todos

+ diff --git a/architecture-examples/angularjs/js/controllers/todoCtrl.js b/architecture-examples/angularjs/js/controllers/todoCtrl.js index 0ddc68d9a7..f023836e8c 100644 --- a/architecture-examples/angularjs/js/controllers/todoCtrl.js +++ b/architecture-examples/angularjs/js/controllers/todoCtrl.js @@ -1,4 +1,4 @@ -/*global todomvc */ +/*global todomvc, angular */ 'use strict'; /** @@ -12,11 +12,13 @@ todomvc.controller('TodoCtrl', function TodoCtrl($scope, $location, todoStorage, $scope.newTodo = ''; $scope.editedTodo = null; - $scope.$watch('todos', function () { - $scope.remainingCount = filterFilter(todos, {completed: false}).length; + $scope.$watch('todos', function (newValue, oldValue) { + $scope.remainingCount = filterFilter(todos, { completed: false }).length; $scope.completedCount = todos.length - $scope.remainingCount; $scope.allChecked = !$scope.remainingCount; - todoStorage.put(todos); + if (newValue !== oldValue) { // This prevents unneeded calls to the local storage + todoStorage.put(todos); + } }, true); if ($location.path() === '') { @@ -32,12 +34,13 @@ todomvc.controller('TodoCtrl', function TodoCtrl($scope, $location, todoStorage, }); $scope.addTodo = function () { - if (!$scope.newTodo.length) { + var newTodo = $scope.newTodo.trim(); + if (!newTodo.length) { return; } todos.push({ - title: $scope.newTodo, + title: newTodo, completed: false }); @@ -46,15 +49,24 @@ todomvc.controller('TodoCtrl', function TodoCtrl($scope, $location, todoStorage, $scope.editTodo = function (todo) { $scope.editedTodo = todo; + // Clone the original todo to restore it on demand. + $scope.originalTodo = angular.extend({}, todo); }; $scope.doneEditing = function (todo) { $scope.editedTodo = null; + todo.title = todo.title.trim(); + if (!todo.title) { $scope.removeTodo(todo); } }; + $scope.revertEditing = function (todo) { + todos[todos.indexOf(todo)] = $scope.originalTodo; + $scope.doneEditing($scope.originalTodo); + }; + $scope.removeTodo = function (todo) { todos.splice(todos.indexOf(todo), 1); }; diff --git a/architecture-examples/angularjs/js/directives/todoEscape.js b/architecture-examples/angularjs/js/directives/todoEscape.js new file mode 100644 index 0000000000..41bc9a275d --- /dev/null +++ b/architecture-examples/angularjs/js/directives/todoEscape.js @@ -0,0 +1,18 @@ +/*global todomvc */ +'use strict'; + +/** + * Directive that executes an expression when the element it is applied to gets + * an `escape` keydown event. + */ +todomvc.directive('todoBlur', function () { + var ESCAPE_KEY = 27; + return function (scope, elem, attrs) { + elem.bind('keydown', function (event) { + if (event.keyCode === ESCAPE_KEY) { + scope.$apply(attrs.todoEscape); + } + }); + }; +}); + diff --git a/architecture-examples/angularjs/readme.md b/architecture-examples/angularjs/readme.md new file mode 100644 index 0000000000..d730713115 --- /dev/null +++ b/architecture-examples/angularjs/readme.md @@ -0,0 +1,36 @@ +# AngularJS TodoMVC Example + +> HTML is great for declaring static documents, but it falters when we try to use it for declaring dynamic views in web-applications. AngularJS lets you extend HTML vocabulary for your application. The resulting environment is extraordinarily expressive, readable, and quick to develop. + +> _[AngularJS - angularjs.org](http://angularjs.org)_ + + +## Learning AngularJS +The [AngularJS website](http://angularjs.org) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Tutorial](http://docs.angularjs.org/tutorial) +* [API Reference](http://docs.angularjs.org/api) +* [Developer Guide](http://docs.angularjs.org/guide) +* [Applications built with AngularJS](http://builtwith.angularjs.org) +* [Blog](http://blog.angularjs.org) +* [FAQ](http://docs.angularjs.org/misc/faq) +* [AngularJS Meetups](http://www.youtube.com/angularjs) + +Articles and guides from the community: + +* [Code School AngularJS course](http://www.codeschool.com/code_tv/angularjs-part-1) +* [5 Awesome AngularJS Features](http://net.tutsplus.com/tutorials/javascript-ajax/5-awesome-angularjs-features) +* [Using Yeoman with AngularJS](http://briantford.com/blog/angular-yeoman.html) +* [me&ngular - an introduction to MVW](http://stephenplusplus.github.io/meangular) + +Get help from other AngularJS users: + +* [Walkthroughs and Tutorials on YouTube](http://www.youtube.com/playlist?list=PL1w1q3fL4pmgqpzb-XhG7Clgi67d_OHXz) +* [Google Groups mailing list](https://groups.google.com/forum/?fromgroups#!forum/angular) +* [angularjs on Stack Overflow](http://stackoverflow.com/questions/tagged/angularjs) +* [AngularJS on Twitter](https://twitter.com/angularjs) +* [AngularjS on Google +](https://plus.google.com/+AngularJS/posts) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ diff --git a/architecture-examples/angularjs/test/config/testacular.conf.js b/architecture-examples/angularjs/test/config/testacular.conf.js index c1ebfdafd4..8b40a7197d 100644 --- a/architecture-examples/angularjs/test/config/testacular.conf.js +++ b/architecture-examples/angularjs/test/config/testacular.conf.js @@ -3,8 +3,8 @@ basePath = '../../'; files = [ JASMINE, JASMINE_ADAPTER, - 'components/angular/angular.js', - 'components/angular-mocks/angular-mocks.js', + 'bower_components/angular/angular.js', + 'bower_components/angular-mocks/angular-mocks.js', 'js/**/*.js', 'test/unit/**/*.js' ]; diff --git a/architecture-examples/angularjs/test/package.json b/architecture-examples/angularjs/test/package.json index fdfecf7e10..dc5b2e9b8f 100644 --- a/architecture-examples/angularjs/test/package.json +++ b/architecture-examples/angularjs/test/package.json @@ -1,12 +1,13 @@ { - "name": "todomvc-angular-tests", - "description": "Unit tests for the AngularJS example of TodoMVC", - "author": "Pascal Hartig ", - "version": "1.0.0", - "devDependencies": { - "testacular": "~ 0.4.0" - }, - "scripts": { - "test": "testacular start config/testacular.conf.js" - } + "name": "todomvc-angular-tests", + "description": "Unit tests for the AngularJS example of TodoMVC", + "author": "Pascal Hartig ", + "version": "1.0.0", + "devDependencies": { + "karma": "~0.8.5" + }, + "scripts": { + "test": "karma start config/testacular.conf.js" + }, + "dependencies": {} } diff --git a/architecture-examples/angularjs/test/unit/todoCtrlSpec.js b/architecture-examples/angularjs/test/unit/todoCtrlSpec.js index abba5552d9..25edced13c 100644 --- a/architecture-examples/angularjs/test/unit/todoCtrlSpec.js +++ b/architecture-examples/angularjs/test/unit/todoCtrlSpec.js @@ -4,13 +4,23 @@ describe('Todo Controller', function () { var ctrl, scope; + var todoList; + var todoStorage = { + storage: {}, + get: function () { + return this.storage; + }, + put: function (value) { + this.storage = value; + } + }; // Load the module containing the app, only 'ng' is loaded by default. beforeEach(module('todomvc')); beforeEach(inject(function ($controller, $rootScope) { scope = $rootScope.$new(); - ctrl = $controller('TodoCtrl', {$scope: scope}); + ctrl = $controller('TodoCtrl', { $scope: scope }); })); it('should not have an edited Todo on start', function () { @@ -60,17 +70,44 @@ }); }); + describe('having no Todos', function () { + var ctrl; + + beforeEach(inject(function ($controller) { + todoStorage.storage = []; + ctrl = $controller('TodoCtrl', { + $scope: scope, + todoStorage: todoStorage + }); + scope.$digest(); + })); + + it('should not add empty Todos', function () { + scope.newTodo = ''; + scope.addTodo(); + scope.$digest(); + expect(scope.todos.length).toBe(0); + }); + + it('should not add items consisting only of whitespaces', function () { + scope.newTodo = ' '; + scope.addTodo(); + scope.$digest(); + expect(scope.todos.length).toBe(0); + }); + + + it('should trim whitespace from new Todos', function () { + scope.newTodo = ' buy some unicorns '; + scope.addTodo(); + scope.$digest(); + expect(scope.todos.length).toBe(1); + expect(scope.todos[0].title).toBe('buy some unicorns'); + }); + }); + describe('having some saved Todos', function () { - var todoList, - todoStorage = { - storage: {}, - get: function () { - return this.storage; - }, - put: function (value) { - this.storage = value; - } - }; + var ctrl; beforeEach(inject(function ($controller) { todoList = [{ @@ -117,6 +154,14 @@ expect(scope.todos.length).toBe(4); }); + it('should trim Todos on saving', function () { + var todo = todoList[0]; + todo.title = ' buy moar unicorns '; + + scope.doneEditing(todo); + expect(scope.todos[0].title).toBe('buy moar unicorns'); + }); + it('clearCompletedTodos() should clear completed Todos', function () { scope.clearCompletedTodos(); expect(scope.todos.length).toBe(3); @@ -127,6 +172,15 @@ scope.$digest(); expect(scope.completedCount).toBe(5); }); + + it('revertTodo() get a Todo to its previous state', function () { + var todo = todoList[0]; + scope.editTodo(todo); + todo.title = 'Unicorn sparkly skypuffles.'; + scope.revertEditing(todo); + scope.$digest(); + expect(scope.todos[0].title).toBe('Uncompleted Item 0'); + }); }); }); }()); diff --git a/architecture-examples/backbone/bower_components/todomvc-common/base.css b/architecture-examples/backbone/bower_components/todomvc-common/base.css index 8d1db3a696..3e6bfaf38d 100644 --- a/architecture-examples/backbone/bower_components/todomvc-common/base.css +++ b/architecture-examples/backbone/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -412,3 +412,144 @@ label[for='toggle-all'] { .hidden{ display:none; } + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/architecture-examples/backbone/bower_components/todomvc-common/base.js b/architecture-examples/backbone/bower_components/todomvc-common/base.js index 3fd166d061..099da60dd1 100644 --- a/architecture-examples/backbone/bower_components/todomvc-common/base.js +++ b/architecture-examples/backbone/bower_components/todomvc-common/base.js @@ -1,38 +1,209 @@ (function () { 'use strict'; + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + if (location.hostname === 'todomvc.com') { window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); } - function getSourcePath() { - // If accessed via addyosmani.github.io/todomvc/, strip the project path. - if (location.hostname.indexOf('github.io') > 0) { - return location.pathname.replace(/todomvc\//, ''); + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); } - return location.pathname; } - function appendSourceLink() { - var sourceLink = document.createElement('a'); - var paragraph = document.createElement('p'); - var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } - if (footer) { - sourceLink.href = urlBase + getSourcePath(); - sourceLink.appendChild(document.createTextNode('Check out the source')); - paragraph.appendChild(sourceLink); - footer.appendChild(paragraph); + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; } - function redirect() { - if (location.hostname === 'addyosmani.github.io') { - location.href = location.href.replace('addyosmani.github.io/todomvc', 'todomvc.com'); + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); } } - appendSourceLink(); + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + redirect(); + getFile('learn.json', Learn); })(); diff --git a/architecture-examples/backbone/index.html b/architecture-examples/backbone/index.html index 801bf8eb9b..892a1ab630 100644 --- a/architecture-examples/backbone/index.html +++ b/architecture-examples/backbone/index.html @@ -1,8 +1,8 @@ - + - + Backbone.js • TodoMVC @@ -56,8 +56,8 @@

todos

- - + + diff --git a/architecture-examples/backbone/js/collections/todos.js b/architecture-examples/backbone/js/collections/todos.js index 4b73a7b03d..ac4d837b49 100644 --- a/architecture-examples/backbone/js/collections/todos.js +++ b/architecture-examples/backbone/js/collections/todos.js @@ -9,7 +9,7 @@ var app = app || {}; // The collection of todos is backed by *localStorage* instead of a remote // server. - var TodoList = Backbone.Collection.extend({ + var Todos = Backbone.Collection.extend({ // Reference to this collection's model. model: app.Todo, @@ -44,5 +44,5 @@ var app = app || {}; }); // Create our global collection of **Todos**. - app.Todos = new TodoList(); + app.todos = new Todos(); })(); diff --git a/architecture-examples/backbone/js/routers/router.js b/architecture-examples/backbone/js/routers/router.js index a1f488a0b5..f7d618f7aa 100644 --- a/architecture-examples/backbone/js/routers/router.js +++ b/architecture-examples/backbone/js/routers/router.js @@ -6,7 +6,7 @@ var app = app || {}; // Todo Router // ---------- - var Workspace = Backbone.Router.extend({ + var TodoRouter = Backbone.Router.extend({ routes: { '*filter': 'setFilter' }, @@ -17,10 +17,10 @@ var app = app || {}; // Trigger a collection filter event, causing hiding/unhiding // of Todo view items - app.Todos.trigger('filter'); + app.todos.trigger('filter'); } }); - app.TodoRouter = new Workspace(); + app.TodoRouter = new TodoRouter(); Backbone.history.start(); })(); diff --git a/architecture-examples/backbone/js/views/app.js b/architecture-examples/backbone/js/views/app-view.js similarity index 81% rename from architecture-examples/backbone/js/views/app.js rename to architecture-examples/backbone/js/views/app-view.js index 8dd6a3efa4..1bd626a3c0 100644 --- a/architecture-examples/backbone/js/views/app.js +++ b/architecture-examples/backbone/js/views/app-view.js @@ -33,22 +33,22 @@ var app = app || {}; this.$footer = this.$('#footer'); this.$main = this.$('#main'); - this.listenTo(app.Todos, 'add', this.addOne); - this.listenTo(app.Todos, 'reset', this.addAll); - this.listenTo(app.Todos, 'change:completed', this.filterOne); - this.listenTo(app.Todos, 'filter', this.filterAll); - this.listenTo(app.Todos, 'all', this.render); + this.listenTo(app.todos, 'add', this.addOne); + this.listenTo(app.todos, 'reset', this.addAll); + this.listenTo(app.todos, 'change:completed', this.filterOne); + this.listenTo(app.todos, 'filter', this.filterAll); + this.listenTo(app.todos, 'all', this.render); - app.Todos.fetch(); + app.todos.fetch(); }, // Re-rendering the App just means refreshing the statistics -- the rest // of the app doesn't change. render: function () { - var completed = app.Todos.completed().length; - var remaining = app.Todos.remaining().length; + var completed = app.todos.completed().length; + var remaining = app.todos.remaining().length; - if (app.Todos.length) { + if (app.todos.length) { this.$main.show(); this.$footer.show(); @@ -79,7 +79,7 @@ var app = app || {}; // Add all items in the **Todos** collection at once. addAll: function () { this.$('#todo-list').html(''); - app.Todos.each(this.addOne, this); + app.todos.each(this.addOne, this); }, filterOne: function (todo) { @@ -87,14 +87,14 @@ var app = app || {}; }, filterAll: function () { - app.Todos.each(this.filterOne, this); + app.todos.each(this.filterOne, this); }, // Generate the attributes for a new Todo item. newAttributes: function () { return { title: this.$input.val().trim(), - order: app.Todos.nextOrder(), + order: app.todos.nextOrder(), completed: false }; }, @@ -106,20 +106,20 @@ var app = app || {}; return; } - app.Todos.create(this.newAttributes()); + app.todos.create(this.newAttributes()); this.$input.val(''); }, // Clear all completed todo items, destroying their models. clearCompleted: function () { - _.invoke(app.Todos.completed(), 'destroy'); + _.invoke(app.todos.completed(), 'destroy'); return false; }, toggleAllComplete: function () { var completed = this.allCheckbox.checked; - app.Todos.each(function (todo) { + app.todos.each(function (todo) { todo.save({ 'completed': completed }); diff --git a/architecture-examples/backbone/js/views/todos.js b/architecture-examples/backbone/js/views/todo-view.js similarity index 93% rename from architecture-examples/backbone/js/views/todos.js rename to architecture-examples/backbone/js/views/todo-view.js index 9493480325..ed0a0f1a3c 100644 --- a/architecture-examples/backbone/js/views/todos.js +++ b/architecture-examples/backbone/js/views/todo-view.js @@ -67,10 +67,11 @@ var app = app || {}; // Close the `"editing"` mode, saving changes to the todo. close: function () { - var value = this.$input.val().trim(); + var trimmedValue = this.$input.val().trim(); + this.$input.val(trimmedValue); - if (value) { - this.model.save({ title: value }); + if (trimmedValue) { + this.model.save({ title: trimmedValue }); } else { this.clear(); } diff --git a/architecture-examples/backbone/readme.md b/architecture-examples/backbone/readme.md new file mode 100644 index 0000000000..7214c2ab24 --- /dev/null +++ b/architecture-examples/backbone/readme.md @@ -0,0 +1,29 @@ +# Backbone.js TodoMVC Example + +> Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface. + +> _[Backbone.js - backbonejs.org](http://backbonejs.org)_ + + +## Learning Backbone.js + +The [Backbone.js website](http://backbonejs.org) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Annotated source code](http://backbonejs.org/docs/backbone.html) +* [Applications built with Backbone.js](http://backbonejs.org/#examples) +* [FAQ](http://backbonejs.org/#faq) + +Articles and guides from the community: + +* [Developing Backbone.js Applications](http://addyosmani.github.io/backbone-fundamentals) +* [Collection of tutorials, blog posts, and example sites](https://github.com/documentcloud/backbone/wiki/Tutorials%2C-blog-posts-and-example-sites) + +Get help from other Backbone.js users: + +* [Backbone.js on StackOverflow](http://stackoverflow.com/questions/tagged/backbone.js) +* [Google Groups mailing list](https://groups.google.com/forum/#!forum/backbonejs) +* [Backbone.js on Twitter](http://twitter.com/documentcloud) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ diff --git a/architecture-examples/canjs/bower.json b/architecture-examples/canjs/bower.json index c41fbecea9..97087b4751 100644 --- a/architecture-examples/canjs/bower.json +++ b/architecture-examples/canjs/bower.json @@ -3,8 +3,8 @@ "version": "0.0.0", "dependencies": { "jquery": "~1.9.1", - "canjs": "~1.1.4", + "canjs": "~1.1.5", "canjs-localstorage": "~0.1.0", - "todomvc-common": "~0.1.4" + "todomvc-common": "~0.1.6" } } diff --git a/architecture-examples/canjs/bower_components/canjs/can.jquery.js b/architecture-examples/canjs/bower_components/canjs/can.jquery.js index 47239b2dc8..e372869ad8 100644 --- a/architecture-examples/canjs/bower_components/canjs/can.jquery.js +++ b/architecture-examples/canjs/bower_components/canjs/can.jquery.js @@ -1,3675 +1,3744 @@ /*! -* CanJS - 1.1.4 (2013-02-05) +* CanJS - 1.1.5 (2013-03-27) * http://canjs.us/ * Copyright (c) 2013 Bitovi * Licensed MIT */ (function (window, $, undefined) { - // ## can/util/can.js - var can = window.can || {}; - if (typeof GLOBALCAN === 'undefined' || GLOBALCAN !== false) { - window.can = can; - } - - can.isDeferred = function (obj) { - var isFunction = this.isFunction; - // Returns `true` if something looks like a deferred. - return obj && isFunction(obj.then) && isFunction(obj.pipe); - }; - - var cid = 0; - can.cid = function (object, name) { - if (object._cid) { - return object._cid - } else { - return object._cid = (name || "") + (++cid) - } - } - // ## can/util/array/each.js - can.each = function (elements, callback, context) { - var i = 0, - key; - if (elements) { - if (typeof elements.length === 'number' && elements.pop) { - if (elements.attr) { - elements.attr('length'); - } - for (key = elements.length; i < key; i++) { - if (callback.call(context || elements[i], elements[i], i, elements) === false) { - break; - } - } - } else if (elements.hasOwnProperty) { - for (key in elements) { - if (elements.hasOwnProperty(key)) { - if (callback.call(context || elements[key], elements[key], key, elements) === false) { - break; - } - } - } - } - } - return elements; - }; - - // ## can/util/jquery/jquery.js - // _jQuery node list._ - $.extend(can, $, { - trigger: function (obj, event, args) { - if (obj.trigger) { - obj.trigger(event, args); - } else { - $.event.trigger(event, args, obj, true); - } - }, - addEvent: function (ev, cb) { - $([this]).bind(ev, cb); - return this; - }, - removeEvent: function (ev, cb) { - $([this]).unbind(ev, cb); - return this; - }, - // jquery caches fragments, we always needs a new one - buildFragment: function (elems, context) { - var oldFragment = $.buildFragment, - ret; - - elems = [elems]; - // Set context per 1.8 logic - context = context || document; - context = !context.nodeType && context[0] || context; - context = context.ownerDocument || context; - - ret = oldFragment.call(jQuery, elems, context); - - return ret.cacheable ? $.clone(ret.fragment) : ret.fragment || ret; - }, - $: $, - each: can.each - }); - - // Wrap binding functions. - $.each(['bind', 'unbind', 'undelegate', 'delegate'], function (i, func) { - can[func] = function () { - var t = this[func] ? this : $([this]); - t[func].apply(t, arguments); - return this; - }; - }); - - // Wrap modifier functions. - $.each(["append", "filter", "addClass", "remove", "data", "get"], function (i, name) { - can[name] = function (wrapped) { - return wrapped[name].apply(wrapped, can.makeArray(arguments).slice(1)); - }; - }); - - // Memory safe destruction. - var oldClean = $.cleanData; - - $.cleanData = function (elems) { - $.each(elems, function (i, elem) { - if (elem) { - can.trigger(elem, "destroyed", [], false); - } - }); - oldClean(elems); - }; - - // ## can/util/string/string.js - // ##string.js - // _Miscellaneous string utility functions._ - // Several of the methods in this plugin use code adapated from Prototype - // Prototype JavaScript framework, version 1.6.0.1. - // © 2005-2007 Sam Stephenson - var strUndHash = /_|-/, - strColons = /\=\=/, - strWords = /([A-Z]+)([A-Z][a-z])/g, - strLowUp = /([a-z\d])([A-Z])/g, - strDash = /([a-z\d])([A-Z])/g, - strReplacer = /\{([^\}]+)\}/g, - strQuote = /"/g, - strSingleQuote = /'/g, - - // Returns the `prop` property from `obj`. - // If `add` is true and `prop` doesn't exist in `obj`, create it as an - // empty object. - getNext = function (obj, prop, add) { - return prop in obj ? obj[prop] : (add && (obj[prop] = {})); - }, - - // Returns `true` if the object can have properties (no `null`s). - isContainer = function (current) { - return (/^f|^o/).test(typeof current); - }; - - can.extend(can, { - // Escapes strings for HTML. - esc: function (content) { - // Convert bad values into empty strings - var isInvalid = content === null || content === undefined || (isNaN(content) && ("" + content === 'NaN')); - return ("" + (isInvalid ? '' : content)).replace(/&/g, '&').replace(//g, '>').replace(strQuote, '"').replace(strSingleQuote, "'"); - }, - - - getObject: function (name, roots, add) { - - // The parts of the name we are looking up - // `['App','Models','Recipe']` - var parts = name ? name.split('.') : [], - length = parts.length, - current, r = 0, - ret, i; - - // Make sure roots is an `array`. - roots = can.isArray(roots) ? roots : [roots || window]; - - if (!length) { - return roots[0]; - } - - // For each root, mark it as current. - while (roots[r]) { - current = roots[r]; - - // Walk current to the 2nd to last object or until there - // is not a container. - for (i = 0; i < length - 1 && isContainer(current); i++) { - current = getNext(current, parts[i], add); - } - - // If we can get a property from the 2nd to last object... - if (isContainer(current)) { - - // Get (and possibly set) the property. - ret = getNext(current, parts[i], add); - - // If there is a value, we exit. - if (ret !== undefined) { - // If `add` is `false`, delete the property - if (add === false) { - delete current[parts[i]]; - } - return ret; - - } - } - r++; - } - }, - // Capitalizes a string. - capitalize: function (s, cache) { - // Used to make newId. - return s.charAt(0).toUpperCase() + s.slice(1); - }, - - // Underscores a string. - underscore: function (s) { - return s.replace(strColons, '/').replace(strWords, '$1_$2').replace(strLowUp, '$1_$2').replace(strDash, '_').toLowerCase(); - }, - // Micro-templating. - sub: function (str, data, remove) { - var obs = []; - - obs.push(str.replace(strReplacer, function (whole, inside) { - - // Convert inside to type. - var ob = can.getObject(inside, data, remove === undefined ? remove : !remove); - - if (ob === undefined) { - obs = null; - return ""; - } - - // If a container, push into objs (which will return objects found). - if (isContainer(ob) && obs) { - obs.push(ob); - return ""; - } - - return "" + ob; - })); - - return obs === null ? obs : (obs.length <= 1 ? obs[0] : obs); - }, - - // These regex's are used throughout the rest of can, so let's make - // them available. - replacer: strReplacer, - undHash: strUndHash - }); - // ## can/construct/construct.js - // ## construct.js - // `can.Construct` - // _This is a modified version of - // [John Resig's class](http://ejohn.org/blog/simple-javascript-inheritance/). - // It provides class level inheritance and callbacks._ - // A private flag used to initialize a new class instance without - // initializing it's bindings. - var initializing = 0; - - - can.Construct = function () { - if (arguments.length) { - return can.Construct.extend.apply(can.Construct, arguments); - } - }; - - - can.extend(can.Construct, { - - newInstance: function () { - // Get a raw instance object (`init` is not called). - var inst = this.instance(), - arg = arguments, - args; - - // Call `setup` if there is a `setup` - if (inst.setup) { - args = inst.setup.apply(inst, arguments); - } - - // Call `init` if there is an `init` - // If `setup` returned `args`, use those as the arguments - if (inst.init) { - inst.init.apply(inst, args || arguments); - } - - return inst; - }, - // Overwrites an object with methods. Used in the `super` plugin. - // `newProps` - New properties to add. - // `oldProps` - Where the old properties might be (used with `super`). - // `addTo` - What we are adding to. - _inherit: function (newProps, oldProps, addTo) { - can.extend(addTo || newProps, newProps || {}) - }, - // used for overwriting a single property. - // this should be used for patching other objects - // the super plugin overwrites this - _overwrite: function (what, oldProps, propName, val) { - what[propName] = val; - }, - // Set `defaults` as the merger of the parent `defaults` and this - // object's `defaults`. If you overwrite this method, make sure to - // include option merging logic. - setup: function (base, fullName) { - this.defaults = can.extend(true, {}, base.defaults, this.defaults); - }, - // Create's a new `class` instance without initializing by setting the - // `initializing` flag. - instance: function () { - - // Prevents running `init`. - initializing = 1; - - var inst = new this(); - - // Allow running `init`. - initializing = 0; - - return inst; - }, - // Extends classes. - extend: function (fullName, klass, proto) { - // Figure out what was passed and normalize it. - if (typeof fullName != 'string') { - proto = klass; - klass = fullName; - fullName = null; - } - - if (!proto) { - proto = klass; - klass = null; - } - proto = proto || {}; - - var _super_class = this, - _super = this.prototype, - name, shortName, namespace, prototype; - - // Instantiate a base class (but only create the instance, - // don't run the init constructor). - prototype = this.instance(); - - // Copy the properties over onto the new prototype. - can.Construct._inherit(proto, _super, prototype); - - // The dummy class constructor. - - - function Constructor() { - // All construction is actually done in the init method. - if (!initializing) { - return this.constructor !== Constructor && arguments.length ? - // We are being called without `new` or we are extending. - arguments.callee.extend.apply(arguments.callee, arguments) : - // We are being called with `new`. - this.constructor.newInstance.apply(this.constructor, arguments); - } - } - - // Copy old stuff onto class (can probably be merged w/ inherit) - for (name in _super_class) { - if (_super_class.hasOwnProperty(name)) { - Constructor[name] = _super_class[name]; - } - } - - // Copy new static properties on class. - can.Construct._inherit(klass, _super_class, Constructor); - - // Setup namespaces. - if (fullName) { - - var parts = fullName.split('.'), - shortName = parts.pop(), - current = can.getObject(parts.join('.'), window, true), - namespace = current, - _fullName = can.underscore(fullName.replace(/\./g, "_")), - _shortName = can.underscore(shortName); - - - - current[shortName] = Constructor; - } - - // Set things that shouldn't be overwritten. - can.extend(Constructor, { - constructor: Constructor, - prototype: prototype, - - namespace: namespace, - - shortName: shortName, - _shortName: _shortName, - - fullName: fullName, - _fullName: _fullName - }); - - // Make sure our prototype looks nice. - Constructor.prototype.constructor = Constructor; - - - // Call the class `setup` and `init` - var t = [_super_class].concat(can.makeArray(arguments)), - args = Constructor.setup.apply(Constructor, t); - - if (Constructor.init) { - Constructor.init.apply(Constructor, args || t); - } - - - return Constructor; - - } - - }); - // ## can/observe/observe.js - // ## observe.js - // `can.Observe` - // _Provides the observable pattern for JavaScript Objects._ - // Returns `true` if something is an object with properties of its own. - var canMakeObserve = function (obj) { - return obj && (can.isArray(obj) || can.isPlainObject(obj) || (obj instanceof can.Observe)); - }, - - // Removes all listeners. - unhookup = function (items, namespace) { - return can.each(items, function (item) { - if (item && item.unbind) { - item.unbind("change" + namespace); - } - }); - }, - // Listens to changes on `val` and "bubbles" the event up. - // `val` - The object to listen for changes on. - // `prop` - The property name is at on. - // `parent` - The parent object of prop. - // `ob` - (optional) The Observe object constructor - // `list` - (optional) The observable list constructor - hookupBubble = function (val, prop, parent, Ob, List) { - Ob = Ob || Observe; - List = List || Observe.List; - - // If it's an `array` make a list, otherwise a val. - if (val instanceof Observe) { - // We have an `observe` already... - // Make sure it is not listening to this already - unhookup([val], parent._cid); - } else if (can.isArray(val)) { - val = new List(val); - } else { - val = new Ob(val); - } - - // Listen to all changes and `batchTrigger` upwards. - val.bind("change" + parent._cid, function () { - // `batchTrigger` the type on this... - var args = can.makeArray(arguments), - ev = args.shift(); - args[0] = (prop === "*" ? [parent.indexOf(val), args[0]] : [prop, args[0]]).join("."); - - // track objects dispatched on this observe - ev.triggeredNS = ev.triggeredNS || {}; - - // if it has already been dispatched exit - if (ev.triggeredNS[parent._cid]) { - return; - } - - ev.triggeredNS[parent._cid] = true; - // send change event with modified attr to parent - can.trigger(parent, ev, args); - // send modified attr event to parent - //can.trigger(parent, args[0], args); - }); - - return val; - }, - - // An `id` to track events for a given observe. - observeId = 0, - // A helper used to serialize an `Observe` or `Observe.List`. - // `observe` - The observable. - // `how` - To serialize with `attr` or `serialize`. - // `where` - To put properties, in an `{}` or `[]`. - serialize = function (observe, how, where) { - // Go through each property. - observe.each(function (val, name) { - // If the value is an `object`, and has an `attrs` or `serialize` function. - where[name] = canMakeObserve(val) && can.isFunction(val[how]) ? - // Call `attrs` or `serialize` to get the original data back. - val[how]() : - // Otherwise return the value. - val; - }); - return where; - }, - $method = function (name) { - return function () { - return can[name].apply(this, arguments); - }; - }, - bind = $method('addEvent'), - unbind = $method('removeEvent'), - attrParts = function (attr) { - return can.isArray(attr) ? attr : ("" + attr).split("."); - }, - // Which batch of events this is for -- might not want to send multiple - // messages on the same batch. This is mostly for event delegation. - batchNum = 1, - // how many times has start been called without a stop - transactions = 0, - // an array of events within a transaction - batchEvents = [], - stopCallbacks = []; - - - - - var Observe = can.Observe = can.Construct({ - - // keep so it can be overwritten - bind: bind, - unbind: unbind, - id: "id", - canMakeObserve: canMakeObserve, - // starts collecting events - // takes a callback for after they are updated - // how could you hook into after ejs - startBatch: function (batchStopHandler) { - transactions++; - batchStopHandler && stopCallbacks.push(batchStopHandler); - }, - - stopBatch: function (force, callStart) { - if (force) { - transactions = 0; - } else { - transactions--; - } - - if (transactions == 0) { - var items = batchEvents.slice(0), - callbacks = stopCallbacks.slice(0); - batchEvents = []; - stopCallbacks = []; - batchNum++; - callStart && this.startBatch(); - can.each(items, function (args) { - can.trigger.apply(can, args); - }); - can.each(callbacks, function (cb) { - cb; - }); - } - }, - - triggerBatch: function (item, event, args) { - // Don't send events if initalizing. - if (!item._init) { - if (transactions == 0) { - return can.trigger(item, event, args); - } else { - batchEvents.push([ - item, - { - type: event, - batchNum: batchNum - }, - args]); - } - } - }, - - keys: function (observe) { - var keys = []; - Observe.__reading && Observe.__reading(observe, '__keys'); - for (var keyName in observe._data) { - keys.push(keyName); - } - return keys; - } - }, - - { - setup: function (obj) { - // `_data` is where we keep the properties. - this._data = {}; - - // The namespace this `object` uses to listen to events. - can.cid(this, ".observe"); - // Sets all `attrs`. - this._init = 1; - this.attr(obj); - this.bind('change' + this._cid, can.proxy(this._changes, this)); - delete this._init; - }, - _changes: function (ev, attr, how, newVal, oldVal) { - Observe.triggerBatch(this, { - type: attr, - batchNum: ev.batchNum - }, [newVal, oldVal]); - }, - _triggerChange: function (attr, how, newVal, oldVal) { - Observe.triggerBatch(this, "change", can.makeArray(arguments)) - }, - - attr: function (attr, val) { - // This is super obfuscated for space -- basically, we're checking - // if the type of the attribute is not a `number` or a `string`. - var type = typeof attr; - if (type !== "string" && type !== "number") { - return this._attrs(attr, val) - } else if (val === undefined) { // If we are getting a value. - // Let people know we are reading. - Observe.__reading && Observe.__reading(this, attr) - return this._get(attr) - } else { - // Otherwise we are setting. - this._set(attr, val); - return this; - } - }, - - each: function () { - Observe.__reading && Observe.__reading(this, '__keys'); - return can.each.apply(undefined, [this.__get()].concat(can.makeArray(arguments))) - }, - - removeAttr: function (attr) { - // Convert the `attr` into parts (if nested). - var parts = attrParts(attr), - // The actual property to remove. - prop = parts.shift(), - // The current value. - current = this._data[prop]; - - // If we have more parts, call `removeAttr` on that part. - if (parts.length) { - return current.removeAttr(parts) - } else { - if (prop in this._data) { - // Otherwise, `delete`. - delete this._data[prop]; - // Create the event. - if (!(prop in this.constructor.prototype)) { - delete this[prop] - } - // Let others know the number of keys have changed - Observe.triggerBatch(this, "__keys"); - this._triggerChange(prop, "remove", undefined, current); - - } - return current; - } - }, - // Reads a property from the `object`. - _get: function (attr) { - // break up the attr (`"foo.bar"`) into `["foo","bar"]` - var parts = attrParts(attr), - // get the value of the first attr name (`"foo"`) - current = this.__get(parts.shift()); - // if there are other attributes to read - return parts.length ? - // and current has a value - current ? - // lookup the remaining attrs on current - current._get(parts) : - // or if there's no current, return undefined - undefined : - // if there are no more parts, return current - current; - }, - // Reads a property directly if an `attr` is provided, otherwise - // returns the "real" data object itself. - __get: function (attr) { - return attr ? this._data[attr] : this._data; - }, - // Sets `attr` prop as value on this object where. - // `attr` - Is a string of properties or an array of property values. - // `value` - The raw value to set. - _set: function (attr, value) { - // Convert `attr` to attr parts (if it isn't already). - var parts = attrParts(attr), - // The immediate prop we are setting. - prop = parts.shift(), - // The current value. - current = this.__get(prop); - - // If we have an `object` and remaining parts. - if (canMakeObserve(current) && parts.length) { - // That `object` should set it (this might need to call attr). - current._set(parts, value) - } else if (!parts.length) { - // We're in "real" set territory. - if (this.__convert) { - value = this.__convert(prop, value) - } - this.__set(prop, value, current) - } else { - throw "can.Observe: Object does not exist" - } - }, - __set: function (prop, value, current) { - - // Otherwise, we are setting it on this `object`. - // TODO: Check if value is object and transform - // are we changing the value. - if (value !== current) { - // Check if we are adding this for the first time -- - // if we are, we need to create an `add` event. - var changeType = this.__get().hasOwnProperty(prop) ? "set" : "add"; - - // Set the value on data. - this.___set(prop, - - // If we are getting an object. - canMakeObserve(value) ? - - // Hook it up to send event. - hookupBubble(value, prop, this) : - // Value is normal. - value); - - if (changeType == "add") { - // If there is no current value, let others know that - // the the number of keys have changed - Observe.triggerBatch(this, "__keys", undefined); - - } - // `batchTrigger` the change event. - this._triggerChange(prop, changeType, value, current); - - //Observe.triggerBatch(this, prop, [value, current]); - // If we can stop listening to our old value, do it. - current && unhookup([current], this._cid); - } - - }, - // Directly sets a property on this `object`. - ___set: function (prop, val) { - this._data[prop] = val; - // Add property directly for easy writing. - // Check if its on the `prototype` so we don't overwrite methods like `attrs`. - if (!(prop in this.constructor.prototype)) { - this[prop] = val - } - }, - - - bind: bind, - - unbind: unbind, - - serialize: function () { - return serialize(this, 'serialize', {}); - }, - - _attrs: function (props, remove) { - - if (props === undefined) { - return serialize(this, 'attr', {}) - } - - props = can.extend({}, props); - var prop, self = this, - newVal; - Observe.startBatch(); - this.each(function (curVal, prop) { - newVal = props[prop]; - - // If we are merging... - if (newVal === undefined) { - remove && self.removeAttr(prop); - return; - } - - if (self.__convert) { - newVal = self.__convert(prop, newVal) - } - - // if we're dealing with models, want to call _set to let converter run - if (newVal instanceof can.Observe) { - self.__set(prop, newVal, curVal) - // if its an object, let attr merge - } else if (canMakeObserve(curVal) && canMakeObserve(newVal) && curVal.attr) { - curVal.attr(newVal, remove) - // otherwise just set - } else if (curVal != newVal) { - self.__set(prop, newVal, curVal) - } - - delete props[prop]; - }) - // Add remaining props. - for (var prop in props) { - newVal = props[prop]; - this._set(prop, newVal) - } - Observe.stopBatch() - return this; - }, - - - compute: function (prop) { - var self = this, - computer = function (val) { - return self.attr(prop, val); - }; - - return can.compute ? can.compute(computer) : computer; - } - }); - // Helpers for `observable` lists. - var splice = [].splice, - list = Observe( - - { - setup: function (instances, options) { - this.length = 0; - can.cid(this, ".observe") - this._init = 1; - this.push.apply(this, can.makeArray(instances || [])); - this.bind('change' + this._cid, can.proxy(this._changes, this)); - can.extend(this, options); - delete this._init; - }, - _triggerChange: function (attr, how, newVal, oldVal) { - - Observe.prototype._triggerChange.apply(this, arguments) - // `batchTrigger` direct add and remove events... - if (!~attr.indexOf('.')) { - - if (how === 'add') { - Observe.triggerBatch(this, how, [newVal, +attr]); - Observe.triggerBatch(this, 'length', [this.length]); - } else if (how === 'remove') { - Observe.triggerBatch(this, how, [oldVal, +attr]); - Observe.triggerBatch(this, 'length', [this.length]); - } else { - Observe.triggerBatch(this, how, [newVal, +attr]) - } - - } - - }, - __get: function (attr) { - return attr ? this[attr] : this; - }, - ___set: function (attr, val) { - this[attr] = val; - if (+attr >= this.length) { - this.length = (+attr + 1) - } - }, - // Returns the serialized form of this list. - serialize: function () { - return serialize(this, 'serialize', []); - }, - - splice: function (index, howMany) { - var args = can.makeArray(arguments), - i; - - for (i = 2; i < args.length; i++) { - var val = args[i]; - if (canMakeObserve(val)) { - args[i] = hookupBubble(val, "*", this) - } - } - if (howMany === undefined) { - howMany = args[1] = this.length - index; - } - var removed = splice.apply(this, args); - can.Observe.startBatch() - if (howMany > 0) { - this._triggerChange("" + index, "remove", undefined, removed); - unhookup(removed, this._cid); - } - if (args.length > 2) { - this._triggerChange("" + index, "add", args.slice(2), removed); - } - can.Observe.stopBatch(); - return removed; - }, - - _attrs: function (items, remove) { - if (items === undefined) { - return serialize(this, 'attr', []); - } - - // Create a copy. - items = can.makeArray(items); - - Observe.startBatch(); - this._updateAttrs(items, remove); - Observe.stopBatch() - }, - - _updateAttrs: function (items, remove) { - var len = Math.min(items.length, this.length); - - for (var prop = 0; prop < len; prop++) { - var curVal = this[prop], - newVal = items[prop]; - - if (canMakeObserve(curVal) && canMakeObserve(newVal)) { - curVal.attr(newVal, remove) - } else if (curVal != newVal) { - this._set(prop, newVal) - } else { - - } - } - if (items.length > this.length) { - // Add in the remaining props. - this.push.apply(this, items.slice(this.length)); - } else if (items.length < this.length && remove) { - this.splice(items.length) - } - } - }), - - // Converts to an `array` of arguments. - getArgs = function (args) { - return args[0] && can.isArray(args[0]) ? args[0] : can.makeArray(args); - }; - // Create `push`, `pop`, `shift`, and `unshift` - can.each({ - - push: "length", - - unshift: 0 - }, - // Adds a method - // `name` - The method name. - // `where` - Where items in the `array` should be added. - - - function (where, name) { - var orig = [][name] - list.prototype[name] = function () { - // Get the items being added. - var args = [], - // Where we are going to add items. - len = where ? this.length : 0, - i = arguments.length, - res, val, constructor = this.constructor; - - // Go through and convert anything to an `observe` that needs to be converted. - while (i--) { - val = arguments[i]; - args[i] = canMakeObserve(val) ? hookupBubble(val, "*", this, this.constructor.Observe, this.constructor) : val; - } - - // Call the original method. - res = orig.apply(this, args); - - if (!this.comparator || !args.length) { - this._triggerChange("" + len, "add", args, undefined); - } - - return res; - } - }); - - can.each({ - - pop: "length", - - shift: 0 - }, - // Creates a `remove` type method - - - function (where, name) { - list.prototype[name] = function () { - - var args = getArgs(arguments), - len = where && this.length ? this.length - 1 : 0; - - var res = [][name].apply(this, args) - - // Create a change where the args are - // `*` - Change on potentially multiple properties. - // `remove` - Items removed. - // `undefined` - The new values (there are none). - // `res` - The old, removed values (should these be unbound). - // `len` - Where these items were removed. - this._triggerChange("" + len, "remove", undefined, [res]) - - if (res && res.unbind) { - res.unbind("change" + this._cid) - } - return res; - } - }); - - can.extend(list.prototype, { - - indexOf: function (item) { - this.attr('length') - return can.inArray(item, this) - }, - - - join: [].join, - - - slice: function () { - var temp = Array.prototype.slice.apply(this, arguments); - return new this.constructor(temp); - }, - - - concat: function () { - var args = []; - can.each(can.makeArray(arguments), function (arg, i) { - args[i] = arg instanceof can.Observe.List ? arg.serialize() : arg; - }); - return new this.constructor(Array.prototype.concat.apply(this.serialize(), args)); - }, - - - forEach: function (cb, thisarg) { - can.each(this, cb, thisarg || this); - }, - - - replace: function (newList) { - if (can.isDeferred(newList)) { - newList.then(can.proxy(this.replace, this)); - } else { - this.splice.apply(this, [0, this.length].concat(can.makeArray(newList || []))); - } - - return this; - } - }); - - Observe.List = list; - Observe.setup = function () { - can.Construct.setup.apply(this, arguments); - // I would prefer not to do it this way. It should - // be using the attributes plugin to do this type of conversion. - this.List = Observe.List({ - Observe: this - }, {}); - } - // ## can/model/model.js - - // ## model.js - // `can.Model` - // _A `can.Observe` that connects to a RESTful interface._ - // Generic deferred piping function - var pipe = function (def, model, func) { - var d = new can.Deferred(); - def.then(function () { - var args = can.makeArray(arguments); - args[0] = model[func](args[0]); - d.resolveWith(d, args); - }, function () { - d.rejectWith(this, arguments); - }); - - if (typeof def.abort === 'function') { - d.abort = function () { - return def.abort(); - } - } - - return d; - }, - modelNum = 0, - ignoreHookup = /change.observe\d+/, - getId = function (inst) { - // Instead of using attr, use __get for performance. - // Need to set reading - can.Observe.__reading && can.Observe.__reading(inst, inst.constructor.id) - return inst.__get(inst.constructor.id); - }, - // Ajax `options` generator function - ajax = function (ajaxOb, data, type, dataType, success, error) { - - var params = {}; - - // If we get a string, handle it. - if (typeof ajaxOb == "string") { - // If there's a space, it's probably the type. - var parts = ajaxOb.split(/\s/); - params.url = parts.pop(); - if (parts.length) { - params.type = parts.pop(); - } - } else { - can.extend(params, ajaxOb); - } - - // If we are a non-array object, copy to a new attrs. - params.data = typeof data == "object" && !can.isArray(data) ? can.extend(params.data || {}, data) : data; - - // Get the url with any templated values filled out. - params.url = can.sub(params.url, params.data, true); - - return can.ajax(can.extend({ - type: type || "post", - dataType: dataType || "json", - success: success, - error: error - }, params)); - }, - makeRequest = function (self, type, success, error, method) { - var deferred, args = [self.serialize()], - // The model. - model = self.constructor, - jqXHR; - - // `destroy` does not need data. - if (type == 'destroy') { - args.shift(); - } - // `update` and `destroy` need the `id`. - if (type !== 'create') { - args.unshift(getId(self)); - } - - - jqXHR = model[type].apply(model, args); - - deferred = jqXHR.pipe(function (data) { - self[method || type + "d"](data, jqXHR); - return self; - }); - - // Hook up `abort` - if (jqXHR.abort) { - deferred.abort = function () { - jqXHR.abort(); - }; - } - - deferred.then(success, error); - return deferred; - }, - - // This object describes how to make an ajax request for each ajax method. - // The available properties are: - // `url` - The default url to use as indicated as a property on the model. - // `type` - The default http request type - // `data` - A method that takes the `arguments` and returns `data` used for ajax. - ajaxMethods = { - - create: { - url: "_shortName", - type: "post" - }, - - update: { - data: function (id, attrs) { - attrs = attrs || {}; - var identity = this.id; - if (attrs[identity] && attrs[identity] !== id) { - attrs["new" + can.capitalize(id)] = attrs[identity]; - delete attrs[identity]; - } - attrs[identity] = id; - return attrs; - }, - type: "put" - }, - - destroy: { - type: "delete", - data: function (id) { - var args = {}; - args.id = args[this.id] = id; - return args; - } - }, - - findAll: { - url: "_shortName" - }, - - findOne: {} - }, - // Makes an ajax request `function` from a string. - // `ajaxMethod` - The `ajaxMethod` object defined above. - // `str` - The string the user provided. Ex: `findAll: "/recipes.json"`. - ajaxMaker = function (ajaxMethod, str) { - // Return a `function` that serves as the ajax method. - return function (data) { - // If the ajax method has it's own way of getting `data`, use that. - data = ajaxMethod.data ? ajaxMethod.data.apply(this, arguments) : - // Otherwise use the data passed in. - data; - // Return the ajax method with `data` and the `type` provided. - return ajax(str || this[ajaxMethod.url || "_url"], data, ajaxMethod.type || "get") - } - } - - - - can.Model = can.Observe({ - fullName: "can.Model", - setup: function (base) { - // create store here if someone wants to use model without inheriting from it - this.store = {}; - can.Observe.setup.apply(this, arguments); - // Set default list as model list - if (!can.Model) { - return; - } - this.List = ML({ - Observe: this - }, {}); - var self = this, - clean = can.proxy(this._clean, self); - - - // go through ajax methods and set them up - can.each(ajaxMethods, function (method, name) { - // if an ajax method is not a function, it's either - // a string url like findAll: "/recipes" or an - // ajax options object like {url: "/recipes"} - if (!can.isFunction(self[name])) { - // use ajaxMaker to convert that into a function - // that returns a deferred with the data - self[name] = ajaxMaker(method, self[name]); - } - // check if there's a make function like makeFindAll - // these take deferred function and can do special - // behavior with it (like look up data in a store) - if (self["make" + can.capitalize(name)]) { - // pass the deferred method to the make method to get back - // the "findAll" method. - var newMethod = self["make" + can.capitalize(name)](self[name]); - can.Construct._overwrite(self, base, name, function () { - // increment the numer of requests - this._reqs++; - var def = newMethod.apply(this, arguments); - var then = def.then(clean, clean); - then.abort = def.abort; - - // attach abort to our then and return it - return then; - }) - } - }); - - if (self.fullName == "can.Model" || !self.fullName) { - self.fullName = "Model" + (++modelNum); - } - // Add ajax converters. - this._reqs = 0; - this._url = this._shortName + "/{" + this.id + "}" - }, - _ajax: ajaxMaker, - _clean: function () { - this._reqs--; - if (!this._reqs) { - for (var id in this.store) { - if (!this.store[id]._bindings) { - delete this.store[id]; - } - } - } - return arguments[0]; - }, - - models: function (instancesRawData, oldList) { - - if (!instancesRawData) { - return; - } - - if (instancesRawData instanceof this.List) { - return instancesRawData; - } - - // Get the list type. - var self = this, - tmp = [], - res = oldList instanceof can.Observe.List ? oldList : new(self.List || ML), - // Did we get an `array`? - arr = can.isArray(instancesRawData), - - // Did we get a model list? - ml = (instancesRawData instanceof ML), - - // Get the raw `array` of objects. - raw = arr ? - - // If an `array`, return the `array`. - instancesRawData : - - // Otherwise if a model list. - (ml ? - - // Get the raw objects from the list. - instancesRawData.serialize() : - - // Get the object's data. - instancesRawData.data), - i = 0; - - - - if (res.length) { - res.splice(0); - } - - can.each(raw, function (rawPart) { - tmp.push(self.model(rawPart)); - }); - - // We only want one change event so push everything at once - res.push.apply(res, tmp); - - if (!arr) { // Push other stuff onto `array`. - can.each(instancesRawData, function (val, prop) { - if (prop !== 'data') { - res.attr(prop, val); - } - }) - } - return res; - }, - - model: function (attributes) { - if (!attributes) { - return; - } - if (attributes instanceof this) { - attributes = attributes.serialize(); - } - var id = attributes[this.id], - model = (id || id === 0) && this.store[id] ? this.store[id].attr(attributes, this.removeAttr || false) : new this(attributes); - if (this._reqs) { - this.store[attributes[this.id]] = model; - } - return model; - } - }, - - { - - isNew: function () { - var id = getId(this); - return !(id || id === 0); // If `null` or `undefined` - }, - - save: function (success, error) { - return makeRequest(this, this.isNew() ? 'create' : 'update', success, error); - }, - - destroy: function (success, error) { - if (this.isNew()) { - var self = this; - return can.Deferred().done(function (data) { - self.destroyed(data) - }).resolve(self); - } - return makeRequest(this, 'destroy', success, error, 'destroyed'); - }, - - bind: function (eventName) { - if (!ignoreHookup.test(eventName)) { - if (!this._bindings) { - this.constructor.store[this.__get(this.constructor.id)] = this; - this._bindings = 0; - } - this._bindings++; - } - - return can.Observe.prototype.bind.apply(this, arguments); - }, - - unbind: function (eventName) { - if (!ignoreHookup.test(eventName)) { - this._bindings--; - if (!this._bindings) { - delete this.constructor.store[getId(this)]; - } - } - return can.Observe.prototype.unbind.apply(this, arguments); - }, - // Change `id`. - ___set: function (prop, val) { - can.Observe.prototype.___set.call(this, prop, val) - // If we add an `id`, move it to the store. - if (prop === this.constructor.id && this._bindings) { - this.constructor.store[getId(this)] = this; - } - } - }); - - can.each({ - makeFindAll: "models", - makeFindOne: "model" - }, function (method, name) { - can.Model[name] = function (oldFind) { - return function (params, success, error) { - var def = pipe(oldFind.call(this, params), this, method); - def.then(success, error); - // return the original promise - return def; - }; - }; - }); - - can.each([ - - "created", - - "updated", - - "destroyed"], function (funcName) { - can.Model.prototype[funcName] = function (attrs) { - var stub, constructor = this.constructor; - - // Update attributes if attributes have been passed - stub = attrs && typeof attrs == 'object' && this.attr(attrs.attr ? attrs.attr() : attrs); - - // Call event on the instance - can.trigger(this, funcName); - can.trigger(this, "change", funcName) - - - // Call event on the instance's Class - can.trigger(constructor, funcName, this); - }; - }); - - // Model lists are just like `Observe.List` except that when their items are - // destroyed, it automatically gets removed from the list. - var ML = can.Model.List = can.Observe.List({ - setup: function () { - can.Observe.List.prototype.setup.apply(this, arguments); - // Send destroy events. - var self = this; - this.bind('change', function (ev, how) { - if (/\w+\.destroyed/.test(how)) { - var index = self.indexOf(ev.target); - if (index != -1) { - self.splice(index, 1); - } - } - }) - } - }) - - // ## can/util/string/deparam/deparam.js - - // ## deparam.js - // `can.deparam` - // _Takes a string of name value pairs and returns a Object literal that represents those params._ - var digitTest = /^\d+$/, - keyBreaker = /([^\[\]]+)|(\[\])/g, - paramTest = /([^?#]*)(#.*)?$/, - prep = function (str) { - return decodeURIComponent(str.replace(/\+/g, " ")); - }; - - - can.extend(can, { - - deparam: function (params) { - - var data = {}, - pairs, lastPart; - - if (params && paramTest.test(params)) { - - pairs = params.split('&'), - - can.each(pairs, function (pair) { - - var parts = pair.split('='), - key = prep(parts.shift()), - value = prep(parts.join("=")), - current = data; - - parts = key.match(keyBreaker); - - for (var j = 0, l = parts.length - 1; j < l; j++) { - if (!current[parts[j]]) { - // If what we are pointing to looks like an `array` - current[parts[j]] = digitTest.test(parts[j + 1]) || parts[j + 1] == "[]" ? [] : {}; - } - current = current[parts[j]]; - } - lastPart = parts.pop(); - if (lastPart == "[]") { - current.push(value); - } else { - current[lastPart] = value; - } - }); - } - return data; - } - }); - // ## can/route/route.js - // ## route.js - // `can.route` - // _Helps manage browser history (and client state) by synchronizing the - // `window.location.hash` with a `can.Observe`._ - // Helper methods used for matching routes. - var - // `RegExp` used to match route variables of the type ':name'. - // Any word character or a period is matched. - matcher = /\:([\w\.]+)/g, - // Regular expression for identifying &key=value lists. - paramsMatcher = /^(?:&[^=]+=[^&]*)+/, - // Converts a JS Object into a list of parameters that can be - // inserted into an html element tag. - makeProps = function (props) { - var tags = []; - can.each(props, function (val, name) { - tags.push((name === 'className' ? 'class' : name) + '="' + (name === "href" ? val : can.esc(val)) + '"'); - }); - return tags.join(" "); - }, - // Checks if a route matches the data provided. If any route variable - // is not present in the data, the route does not match. If all route - // variables are present in the data, the number of matches is returned - // to allow discerning between general and more specific routes. - matchesData = function (route, data) { - var count = 0, - i = 0, - defaults = {}; - // look at default values, if they match ... - for (var name in route.defaults) { - if (route.defaults[name] === data[name]) { - // mark as matched - defaults[name] = 1; - count++; - } - } - for (; i < route.names.length; i++) { - if (!data.hasOwnProperty(route.names[i])) { - return -1; - } - if (!defaults[route.names[i]]) { - count++; - } - - } - - return count; - }, - onready = !0, - location = window.location, - wrapQuote = function (str) { - return (str + '').replace(/([.?*+\^$\[\]\\(){}|\-])/g, "\\$1"); - }, - each = can.each, - extend = can.extend; - - can.route = function (url, defaults) { - defaults = defaults || {}; - // Extract the variable names and replace with `RegExp` that will match - // an atual URL with values. - var names = [], - test = url.replace(matcher, function (whole, name, i) { - names.push(name); - var next = "\\" + (url.substr(i + whole.length, 1) || can.route._querySeparator); - // a name without a default value HAS to have a value - // a name that has a default value can be empty - // The `\\` is for string-escaping giving single `\` for `RegExp` escaping. - return "([^" + next + "]" + (defaults[name] ? "*" : "+") + ")"; - }); - - // Add route in a form that can be easily figured out. - can.route.routes[url] = { - // A regular expression that will match the route when variable values - // are present; i.e. for `:page/:type` the `RegExp` is `/([\w\.]*)/([\w\.]*)/` which - // will match for any value of `:page` and `:type` (word chars or period). - test: new RegExp("^" + test + "($|" + wrapQuote(can.route._querySeparator) + ")"), - // The original URL, same as the index for this entry in routes. - route: url, - // An `array` of all the variable names in this route. - names: names, - // Default values provided for the variables. - defaults: defaults, - // The number of parts in the URL separated by `/`. - length: url.split('/').length - }; - return can.route; - }; - - extend(can.route, { - - _querySeparator: '&', - _paramsMatcher: paramsMatcher, - - - param: function (data, _setRoute) { - // Check if the provided data keys match the names in any routes; - // Get the one with the most matches. - var route, - // Need to have at least 1 match. - matches = 0, - matchCount, routeName = data.route, - propCount = 0; - - delete data.route; - - each(data, function () { - propCount++; - }); - // Otherwise find route. - each(can.route.routes, function (temp, name) { - // best route is the first with all defaults matching - - matchCount = matchesData(temp, data); - if (matchCount > matches) { - route = temp; - matches = matchCount; - } - if (matchCount >= propCount) { - return false; - } - }); - // If we have a route name in our `can.route` data, and it's - // just as good as what currently matches, use that - if (can.route.routes[routeName] && matchesData(can.route.routes[routeName], data) === matches) { - route = can.route.routes[routeName]; - } - // If this is match... - if (route) { - var cpy = extend({}, data), - // Create the url by replacing the var names with the provided data. - // If the default value is found an empty string is inserted. - res = route.route.replace(matcher, function (whole, name) { - delete cpy[name]; - return data[name] === route.defaults[name] ? "" : encodeURIComponent(data[name]); - }), - after; - // Remove matching default values - each(route.defaults, function (val, name) { - if (cpy[name] === val) { - delete cpy[name]; - } - }); - - // The remaining elements of data are added as - // `&` separated parameters to the url. - after = can.param(cpy); - // if we are paraming for setting the hash - // we also want to make sure the route value is updated - if (_setRoute) { - can.route.attr('route', route.route); - } - return res + (after ? can.route._querySeparator + after : ""); - } - // If no route was found, there is no hash URL, only paramters. - return can.isEmptyObject(data) ? "" : can.route._querySeparator + can.param(data); - }, - - deparam: function (url) { - // See if the url matches any routes by testing it against the `route.test` `RegExp`. - // By comparing the URL length the most specialized route that matches is used. - var route = { - length: -1 - }; - each(can.route.routes, function (temp, name) { - if (temp.test.test(url) && temp.length > route.length) { - route = temp; - } - }); - // If a route was matched. - if (route.length > -1) { - - var // Since `RegExp` backreferences are used in `route.test` (parens) - // the parts will contain the full matched string and each variable (back-referenced) value. - parts = url.match(route.test), - // Start will contain the full matched string; parts contain the variable values. - start = parts.shift(), - // The remainder will be the `&key=value` list at the end of the URL. - remainder = url.substr(start.length - (parts[parts.length - 1] === can.route._querySeparator ? 1 : 0)), - // If there is a remainder and it contains a `&key=value` list deparam it. - obj = (remainder && can.route._paramsMatcher.test(remainder)) ? can.deparam(remainder.slice(1)) : {}; - - // Add the default values for this route. - obj = extend(true, {}, route.defaults, obj); - // Overwrite each of the default values in `obj` with those in - // parts if that part is not empty. - each(parts, function (part, i) { - if (part && part !== can.route._querySeparator) { - obj[route.names[i]] = decodeURIComponent(part); - } - }); - obj.route = route.route; - return obj; - } - // If no route was matched, it is parsed as a `&key=value` list. - if (url.charAt(0) !== can.route._querySeparator) { - url = can.route._querySeparator + url; - } - return can.route._paramsMatcher.test(url) ? can.deparam(url.slice(1)) : {}; - }, - - data: new can.Observe({}), - - routes: {}, - - ready: function (val) { - if (val === false) { - onready = val; - } - if (val === true || onready === true) { - can.route._setup(); - setState(); - } - return can.route; - }, - - url: function (options, merge) { - if (merge) { - options = extend({}, curParams, options) - } - return "#!" + can.route.param(options); - }, - - link: function (name, options, props, merge) { - return "" + name + ""; - }, - - current: function (options) { - return location.hash == "#!" + can.route.param(options) - }, - _setup: function () { - // If the hash changes, update the `can.route.data`. - can.bind.call(window, 'hashchange', setState); - }, - _getHash: function () { - return location.href.split(/#!?/)[1] || ""; - }, - _setHash: function (serialized) { - var path = (can.route.param(serialized, true)); - location.hash = "#!" + path; - return path; - } - }); - - - // The functions in the following list applied to `can.route` (e.g. `can.route.attr('...')`) will - // instead act on the `can.route.data` observe. - each(['bind', 'unbind', 'delegate', 'undelegate', 'attr', 'removeAttr'], function (name) { - can.route[name] = function () { - return can.route.data[name].apply(can.route.data, arguments) - } - }) - - var // A ~~throttled~~ debounced function called multiple times will only fire once the - // timer runs down. Each call resets the timer. - timer, - // Intermediate storage for `can.route.data`. - curParams, - // Deparameterizes the portion of the hash of interest and assign the - // values to the `can.route.data` removing existing values no longer in the hash. - // setState is called typically by hashchange which fires asynchronously - // So it's possible that someone started changing the data before the - // hashchange event fired. For this reason, it will not set the route data - // if the data is changing or the hash already matches the hash that was set. - setState = can.route.setState = function () { - var hash = can.route._getHash(); - curParams = can.route.deparam(hash); - - // if the hash data is currently changing, or - // the hash is what we set it to anyway, do NOT change the hash - if (!changingData || hash !== lastHash) { - can.route.attr(curParams, true); - } - }, - // The last hash caused by a data change - lastHash, - // Are data changes pending that haven't yet updated the hash - changingData; - - // If the `can.route.data` changes, update the hash. - // Using `.serialize()` retrieves the raw data contained in the `observable`. - // This function is ~~throttled~~ debounced so it only updates once even if multiple values changed. - // This might be able to use batchNum and avoid this. - can.route.bind("change", function (ev, attr) { - // indicate that data is changing - changingData = 1; - clearTimeout(timer); - timer = setTimeout(function () { - // indicate that the hash is set to look like the data - changingData = 0; - var serialized = can.route.data.serialize(); - - lastHash = can.route._setHash(serialized); - }, 1); - }); - // `onready` event... - can.bind.call(document, "ready", can.route.ready); - - // Libraries other than jQuery don't execute the document `ready` listener - // if we are already DOM ready - if ((document.readyState === 'complete' || document.readyState === "interactive") && onready) { - can.route.ready(); - } - - // extend route to have a similar property - // that is often checked in mustache to determine - // an object's observability - can.route.constructor.canMakeObserve = can.Observe.canMakeObserve; - - // ## can/control/control.js - // ## control.js - // `can.Control` - // _Controller_ - // Binds an element, returns a function that unbinds. - var bind = function (el, ev, callback) { - - can.bind.call(el, ev, callback); - - return function () { - can.unbind.call(el, ev, callback); - }; - }, - isFunction = can.isFunction, - extend = can.extend, - each = can.each, - slice = [].slice, - paramReplacer = /\{([^\}]+)\}/g, - special = can.getObject("$.event.special", [can]) || {}, - - // Binds an element, returns a function that unbinds. - delegate = function (el, selector, ev, callback) { - can.delegate.call(el, selector, ev, callback); - return function () { - can.undelegate.call(el, selector, ev, callback); - }; - }, - - // Calls bind or unbind depending if there is a selector. - binder = function (el, ev, callback, selector) { - return selector ? delegate(el, can.trim(selector), ev, callback) : bind(el, ev, callback); - }, - - basicProcessor; - - - var Control = can.Control = can.Construct( - - { - // Setup pre-processes which methods are event listeners. - setup: function () { - - // Allow contollers to inherit "defaults" from super-classes as it - // done in `can.Construct` - can.Construct.setup.apply(this, arguments); - - // If you didn't provide a name, or are `control`, don't do anything. - if (can.Control) { - - // Cache the underscored names. - var control = this, - funcName; - - // Calculate and cache actions. - control.actions = {}; - for (funcName in control.prototype) { - if (control._isAction(funcName)) { - control.actions[funcName] = control._action(funcName); - } - } - } - }, - - // Moves `this` to the first argument, wraps it with `jQuery` if it's an element - _shifter: function (context, name) { - - var method = typeof name == "string" ? context[name] : name; - - if (!isFunction(method)) { - method = context[method]; - } - - return function () { - context.called = name; - return method.apply(context, [this.nodeName ? can.$(this) : this].concat(slice.call(arguments, 0))); - }; - }, - - // Return `true` if is an action. - _isAction: function (methodName) { - - var val = this.prototype[methodName], - type = typeof val; - // if not the constructor - return (methodName !== 'constructor') && - // and is a function or links to a function - (type == "function" || (type == "string" && isFunction(this.prototype[val]))) && - // and is in special, a processor, or has a funny character - !! (special[methodName] || processors[methodName] || /[^\w]/.test(methodName)); - }, - // Takes a method name and the options passed to a control - // and tries to return the data necessary to pass to a processor - // (something that binds things). - _action: function (methodName, options) { - - // If we don't have options (a `control` instance), we'll run this - // later. - paramReplacer.lastIndex = 0; - if (options || !paramReplacer.test(methodName)) { - // If we have options, run sub to replace templates `{}` with a - // value from the options or the window - var convertedName = options ? can.sub(methodName, [options, window]) : methodName; - if (!convertedName) { - return null; - } - // If a `{}` template resolves to an object, `convertedName` will be - // an array - var arr = can.isArray(convertedName), - - // Get the name - name = arr ? convertedName[1] : convertedName, - - // Grab the event off the end - parts = name.split(/\s+/g), - event = parts.pop(); - - return { - processor: processors[event] || basicProcessor, - parts: [name, parts.join(" "), event], - delegate: arr ? convertedName[0] : undefined - }; - } - }, - // An object of `{eventName : function}` pairs that Control uses to - // hook up events auto-magically. - processors: {}, - // A object of name-value pairs that act as default values for a - // control instance - defaults: {} - }, - - { - // Sets `this.element`, saves the control in `data, binds event - // handlers. - setup: function (element, options) { - - var cls = this.constructor, - pluginname = cls.pluginName || cls._fullName, - arr; - - // Want the raw element here. - this.element = can.$(element) - - if (pluginname && pluginname !== 'can_control') { - // Set element and `className` on element. - this.element.addClass(pluginname); - } - - (arr = can.data(this.element, "controls")) || can.data(this.element, "controls", arr = []); - arr.push(this); - - // Option merging. - this.options = extend({}, cls.defaults, options); - - // Bind all event handlers. - this.on(); - - // Get's passed into `init`. - return [this.element, this.options]; - }, - - on: function (el, selector, eventName, func) { - if (!el) { - - // Adds bindings. - this.off(); - - // Go through the cached list of actions and use the processor - // to bind - var cls = this.constructor, - bindings = this._bindings, - actions = cls.actions, - element = this.element, - destroyCB = can.Control._shifter(this, "destroy"), - funcName, ready; - - for (funcName in actions) { - // Only push if we have the action and no option is `undefined` - if (actions.hasOwnProperty(funcName) && (ready = actions[funcName] || cls._action(funcName, this.options))) { - bindings.push(ready.processor(ready.delegate || element, ready.parts[2], ready.parts[1], funcName, this)); - } - } - - - // Setup to be destroyed... - // don't bind because we don't want to remove it. - can.bind.call(element, "destroyed", destroyCB); - bindings.push(function (el) { - can.unbind.call(el, "destroyed", destroyCB); - }); - return bindings.length; - } - - if (typeof el == 'string') { - func = eventName; - eventName = selector; - selector = el; - el = this.element; - } - - if (func === undefined) { - func = eventName; - eventName = selector; - selector = null; - } - - if (typeof func == 'string') { - func = can.Control._shifter(this, func); - } - - this._bindings.push(binder(el, eventName, func, selector)); - - return this._bindings.length; - }, - // Unbinds all event handlers on the controller. - off: function () { - var el = this.element[0] - each(this._bindings || [], function (value) { - value(el); - }); - // Adds bindings. - this._bindings = []; - }, - // Prepares a `control` for garbage collection - destroy: function () { - var Class = this.constructor, - pluginName = Class.pluginName || Class._fullName, - controls; - - // Unbind bindings. - this.off(); - - if (pluginName && pluginName !== 'can_control') { - // Remove the `className`. - this.element.removeClass(pluginName); - } - - // Remove from `data`. - controls = can.data(this.element, "controls"); - controls.splice(can.inArray(this, controls), 1); - - can.trigger(this, "destroyed"); // In case we want to know if the `control` is removed. - this.element = null; - } - }); - - var processors = can.Control.processors, - // Processors do the binding. - // They return a function that unbinds when called. - // The basic processor that binds events. - basicProcessor = function (el, event, selector, methodName, control) { - return binder(el, event, can.Control._shifter(control, methodName), selector); - }; - - // Set common events to be processed as a `basicProcessor` - each(["change", "click", "contextmenu", "dblclick", "keydown", "keyup", "keypress", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "reset", "resize", "scroll", "select", "submit", "focusin", "focusout", "mouseenter", "mouseleave", - // #104 - Add touch events as default processors - // TOOD feature detect? - "touchstart", "touchmove", "touchcancel", "touchend", "touchleave"], function (v) { - processors[v] = basicProcessor; - }); - - // ## can/control/route/route.js - - // ## control/route.js - // _Controller route integration._ - can.Control.processors.route = function (el, event, selector, funcName, controller) { - selector = selector || ""; - can.route(selector); - var batchNum, check = function (ev, attr, how) { - if (can.route.attr('route') === (selector) && (ev.batchNum === undefined || ev.batchNum !== batchNum)) { - - batchNum = ev.batchNum; - - var d = can.route.attr(); - delete d.route; - if (can.isFunction(controller[funcName])) { - controller[funcName](d); - } else { - controller[controller[funcName]](d); - } - - } - }; - can.route.bind('change', check); - return function () { - can.route.unbind('change', check); - }; - }; - - // ## can/view/view.js - // ## view.js - // `can.view` - // _Templating abstraction._ - var isFunction = can.isFunction, - makeArray = can.makeArray, - // Used for hookup `id`s. - hookupId = 1, - - $view = can.view = function (view, data, helpers, callback) { - // If helpers is a `function`, it is actually a callback. - if (isFunction(helpers)) { - callback = helpers; - helpers = undefined; - } - - var pipe = function (result) { - return $view.frag(result); - }, - // In case we got a callback, we need to convert the can.view.render - // result to a document fragment - wrapCallback = isFunction(callback) ? - function (frag) { - callback(pipe(frag)); - } : null, - // Get the result. - result = $view.render(view, data, helpers, wrapCallback), - deferred = can.Deferred(); - - if (isFunction(result)) { - return result; - } - - if (can.isDeferred(result)) { - result.done(function (result, data) { - deferred.resolve.call(deferred, pipe(result), data); - }); - return deferred; - } - - // Convert it into a dom frag. - return pipe(result); - }; - - can.extend($view, { - // creates a frag and hooks it up all at once - frag: function (result, parentNode) { - return $view.hookup($view.fragment(result), parentNode); - }, - - // simply creates a frag - // this is used internally to create a frag - // insert it - // then hook it up - fragment: function (result) { - var frag = can.buildFragment(result, document.body); - // If we have an empty frag... - if (!frag.childNodes.length) { - frag.appendChild(document.createTextNode('')); - } - return frag; - }, - - // Convert a path like string into something that's ok for an `element` ID. - toId: function (src) { - return can.map(src.toString().split(/\/|\./g), function (part) { - // Dont include empty strings in toId functions - if (part) { - return part; - } - }).join("_"); - }, - - hookup: function (fragment, parentNode) { - var hookupEls = [], - id, func; - - // Get all `childNodes`. - can.each(fragment.childNodes ? can.makeArray(fragment.childNodes) : fragment, function (node) { - if (node.nodeType === 1) { - hookupEls.push(node); - hookupEls.push.apply(hookupEls, can.makeArray(node.getElementsByTagName('*'))); - } - }); - - // Filter by `data-view-id` attribute. - can.each(hookupEls, function (el) { - if (el.getAttribute && (id = el.getAttribute('data-view-id')) && (func = $view.hookups[id])) { - func(el, parentNode, id); - delete $view.hookups[id]; - el.removeAttribute('data-view-id'); - } - }); - - return fragment; - }, - - - hookups: {}, - - - hook: function (cb) { - $view.hookups[++hookupId] = cb; - return " data-view-id='" + hookupId + "'"; - }, - - - cached: {}, - - cachedRenderers: {}, - - - cache: true, - - - register: function (info) { - this.types["." + info.suffix] = info; - }, - - types: {}, - - - ext: ".ejs", - - - registerScript: function () {}, - - - preload: function () {}, - - - render: function (view, data, helpers, callback) { - // If helpers is a `function`, it is actually a callback. - if (isFunction(helpers)) { - callback = helpers; - helpers = undefined; - } - - // See if we got passed any deferreds. - var deferreds = getDeferreds(data); - - if (deferreds.length) { // Does data contain any deferreds? - // The deferred that resolves into the rendered content... - var deferred = new can.Deferred(), - dataCopy = can.extend({}, data); - - // Add the view request to the list of deferreds. - deferreds.push(get(view, true)) - - // Wait for the view and all deferreds to finish... - can.when.apply(can, deferreds).then(function (resolved) { - // Get all the resolved deferreds. - var objs = makeArray(arguments), - // Renderer is the last index of the data. - renderer = objs.pop(), - // The result of the template rendering with data. - result; - - // Make data look like the resolved deferreds. - if (can.isDeferred(data)) { - dataCopy = usefulPart(resolved); - } - else { - // Go through each prop in data again and - // replace the defferreds with what they resolved to. - for (var prop in data) { - if (can.isDeferred(data[prop])) { - dataCopy[prop] = usefulPart(objs.shift()); - } - } - } - - // Get the rendered result. - result = renderer(dataCopy, helpers); - - // Resolve with the rendered view. - deferred.resolve(result, dataCopy); - - // If there's a `callback`, call it back with the result. - callback && callback(result, dataCopy); - }); - // Return the deferred... - return deferred; - } - else { - // No deferreds! Render this bad boy. - var response, - // If there's a `callback` function - async = isFunction(callback), - // Get the `view` type - deferred = get(view, async); - - // If we are `async`... - if (async) { - // Return the deferred - response = deferred; - // And fire callback with the rendered result. - deferred.then(function (renderer) { - callback(data ? renderer(data, helpers) : renderer); - }) - } else { - // if the deferred is resolved, call the cached renderer instead - // this is because it's possible, with recursive deferreds to - // need to render a view while its deferred is _resolving_. A _resolving_ deferred - // is a deferred that was just resolved and is calling back it's success callbacks. - // If a new success handler is called while resoliving, it does not get fired by - // jQuery's deferred system. So instead of adding a new callback - // we use the cached renderer. - // We also add __view_id on the deferred so we can look up it's cached renderer. - // In the future, we might simply store either a deferred or the cached result. - if (deferred.state() === "resolved" && deferred.__view_id) { - var currentRenderer = $view.cachedRenderers[deferred.__view_id]; - return data ? currentRenderer(data, helpers) : currentRenderer; - } else { - // Otherwise, the deferred is complete, so - // set response to the result of the rendering. - deferred.then(function (renderer) { - response = data ? renderer(data, helpers) : renderer; - }); - } - } - - return response; - } - }, - - - registerView: function (id, text, type, def) { - // Get the renderer function. - var func = (type || $view.types[$view.ext]).renderer(id, text); - def = def || new can.Deferred(); - - // Cache if we are caching. - if ($view.cache) { - $view.cached[id] = def; - def.__view_id = id; - $view.cachedRenderers[id] = func; - } - - // Return the objects for the response's `dataTypes` - // (in this case view). - return def.resolve(func); - } - }); - - // Makes sure there's a template, if not, have `steal` provide a warning. - var checkText = function (text, url) { - if (!text.length) { - - throw "can.view: No template or empty template:" + url; - } - }, - // `Returns a `view` renderer deferred. - // `url` - The url to the template. - // `async` - If the ajax request should be asynchronous. - // Returns a deferred. - get = function (url, async) { - var suffix = url.match(/\.[\w\d]+$/), - type, - // If we are reading a script element for the content of the template, - // `el` will be set to that script element. - el, - // A unique identifier for the view (used for caching). - // This is typically derived from the element id or - // the url for the template. - id, - // The ajax request used to retrieve the template content. - jqXHR; - - //If the url has a #, we assume we want to use an inline template - //from a script element and not current page's HTML - if (url.match(/^#/)) { - url = url.substr(1); - } - // If we have an inline template, derive the suffix from the `text/???` part. - // This only supports ` - diff --git a/architecture-examples/canjs/readme.md b/architecture-examples/canjs/readme.md index 80eeccd63f..6b7eedae80 100644 --- a/architecture-examples/canjs/readme.md +++ b/architecture-examples/canjs/readme.md @@ -1,42 +1,64 @@ -# CanJS +# CanJS TodoMVC Example -CanJS is a client-side, JavaScript framework that makes building rich web applications easy. It provides: +> CanJS is a MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy. - - *can.Model* - for connecting to RESTful JSON interfaces - - *can.View* - for template loading and caching - - *can.Observe* - for key-value binding - - *can.EJS* - live binding templates - - *can.Control* - declarative event bindings - - *can.route* - routing support +> _[CanJS - canjs.com](http://canjs.com)_ -And works with jQuery, Zepto, YUI, Dojo and Mootools. -## CanJS and JavaScriptMVC +## Learning CanJS -*CanJS* is the extracted, more modern and more library-like MVC parts of [JavaScriptMVC](http://javascriptmvc.com) -(formerly known as *jQueryMX*). +The [CanJS website](http://canjs.com) is a great resource for getting started. -*JavaScriptMVC 3.3* uses CanJS for the MVC structure so this TodoMVC example **applies to JavaScriptMVC** as well. -Additionally JavaScriptMVC contains: +Here are some links you may find helpful: -- [CanJS](http://canjs.us) - For the MVC parts +* [Documentation](http://donejs.com/docs.html#!canjs) +* [Why CanJS](http://canjs.com/#why_canjs) +* [Applications built with CanJS](http://canjs.com/#examples) +* [Blog](http://bitovi.com/blog/tag/canjs) +* [Getting started video](http://www.youtube.com/watch?v=GdT4Oq6ZQ68) + +Articles and guides from the community: + +* [Diving into CanJS](http://net.tutsplus.com/tutorials/javascript-ajax/diving-into-canjs) + +Get help from other CanJS users: + +* [CanJS on StackOverflow](http://stackoverflow.com/questions/tagged/canjs) +* [CanJS Forums](http://forum.javascriptmvc.com/#Forum/canjs) +* [CanJS on Twitter](http://twitter.com/canjs) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ + + +## Implementation + +### CanJS and JavaScriptMVC + +CanJS is the extracted, more modern and more library-like MVC parts of [JavaScriptMVC](http://javascriptmvc.com), formerly known as jQueryMX. + +JavaScriptMVC 3.3 uses CanJS for the MVC structure so this TodoMVC example applies to JavaScriptMVC as well. + +Additionally, JavaScriptMVC contains: + +- [CanJS](http://canjs.com) - For the MVC parts - [jQuery++](http://jquerypp.com) - jQuery's missing utils and special events - [StealJS](http://javascriptmvc.com/docs.html#!stealjs) - A JavaScript package manager - [DocumentJS](http://javascriptmvc.com/docs.html#!DocumentJS) - A documentation engine - [FuncUnit](http://funcunit.com) - jQuery style functional unit testing -## View engines + +### View engines CanJS supports both live binding [EJS](http://canjs.us/#can_ejs) and [Mustache/Handlebars](http://canjs.us/#can_mustache) templates. By default the Mustache view will be used but an EJS example is available as well. You can easily change it by modifying the `view` option in the `js/app.js` file: ```js -Models.Todo.findAll({}, function(todos) { +Models.Todo.findAll({}, function (todos) { new Todos('#todoapp', { todos: todos, - state : can.route, - view : 'views/todos.ejs' + state: can.route, + view: 'views/todos.ejs' }); }); ``` diff --git a/architecture-examples/closure/bower_components/todomvc-common/base.css b/architecture-examples/closure/bower_components/todomvc-common/base.css index 8d1db3a696..3e6bfaf38d 100644 --- a/architecture-examples/closure/bower_components/todomvc-common/base.css +++ b/architecture-examples/closure/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -412,3 +412,144 @@ label[for='toggle-all'] { .hidden{ display:none; } + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/architecture-examples/closure/bower_components/todomvc-common/base.js b/architecture-examples/closure/bower_components/todomvc-common/base.js index 3fd166d061..099da60dd1 100644 --- a/architecture-examples/closure/bower_components/todomvc-common/base.js +++ b/architecture-examples/closure/bower_components/todomvc-common/base.js @@ -1,38 +1,209 @@ (function () { 'use strict'; + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + if (location.hostname === 'todomvc.com') { window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); } - function getSourcePath() { - // If accessed via addyosmani.github.io/todomvc/, strip the project path. - if (location.hostname.indexOf('github.io') > 0) { - return location.pathname.replace(/todomvc\//, ''); + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); } - return location.pathname; } - function appendSourceLink() { - var sourceLink = document.createElement('a'); - var paragraph = document.createElement('p'); - var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } - if (footer) { - sourceLink.href = urlBase + getSourcePath(); - sourceLink.appendChild(document.createTextNode('Check out the source')); - paragraph.appendChild(sourceLink); - footer.appendChild(paragraph); + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; } - function redirect() { - if (location.hostname === 'addyosmani.github.io') { - location.href = location.href.replace('addyosmani.github.io/todomvc', 'todomvc.com'); + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); } } - appendSourceLink(); + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + redirect(); + getFile('learn.json', Learn); })(); diff --git a/architecture-examples/closure/index.html b/architecture-examples/closure/index.html index 32d9b04a99..ad07042ead 100644 --- a/architecture-examples/closure/index.html +++ b/architecture-examples/closure/index.html @@ -1,48 +1,48 @@ - - - - - Closure • TodoMVC - - - -
- -
- - -
    -
+ + + + + Closure • TodoMVC + + + +
+ +
+ + +
    +
+
+
-
- - - - - - - - - + + + + + + + + diff --git a/architecture-examples/closure/readme.md b/architecture-examples/closure/readme.md index 25379d7a95..23ed7610c7 100644 --- a/architecture-examples/closure/readme.md +++ b/architecture-examples/closure/readme.md @@ -1,8 +1,39 @@ -# TodoMVC Closure Architecture Example +# Closure Tools TodoMVC Example -## Introduction +> The Closure Tools project is an effort by Google engineers to open source the tools used in many of Google's sites and web applications for use by the wider Web development community. + +> _[Closure Tools - developers.google.com/closure](https://developers.google.com/closure)_ + + +## Learning Closure Tools + +The [Closure Tools website](https://developers.google.com/closure) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Documentation](https://developers.google.com/closure/library/docs/overview) +* [API Reference](http://docs.closure-library.googlecode.com/git/index.html) +* [Blog](http://closuretools.blogspot.com) +* [FAQ](https://developers.google.com/closure/faq) + +Articles and guides from the community: + +* [Examples, walkthroughs, and articles](http://www.googleclosure.com) +* [First Adventure in Google Closure](http://www.codeproject.com/Articles/265364/First-Adventures-in-Google-Closure) + +Get help from other Closure Tools users: + +* [Google Groups mailing list](https://groups.google.com/group/closure-library-discuss) +* [Closure Tools on Twitter](http://twitter.com/closuretools) +* [Closure Tools on Google +](https://plus.google.com/communities/113969319608324762672) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ + + +## Implementation + +Note this project breaks with the convention of the others and uses spaces in place of tabs within JavaScript files. This is to comply with the Google style guidelines which the Closure Linter enforces (see [Linting](#linting) below). -An example making use of the [Closure toolkit](https://developers.google.com/closure/). Note this project breaks with the convention of the others and uses spaces in place of tabs within JavaScript files. This is to comply with the Google style guidelines which the Closure Linter enforces (see Linting below). ## Running @@ -29,6 +60,7 @@ The linter must be installed before use, the installation package is included in (or whatever floats your OSs boat) + ## Compiling To compile the code from the command line run Plovr like so - @@ -37,14 +69,7 @@ To compile the code from the command line run Plovr like so - This will overwrite the js/compiled.js file with the new version, be sure to change the script tag reference in the HTML page. -## Credits - -Template by [Sindre Sorhus](http://github.com/sindresorhus) - -Created by [Chris Price](http://www.scottlogic.co.uk/blog/chris/) -Part of [TodoMVC](http://todomvc.com) - -## License +## Credits -Public Domain +This TodoMVC application was created by [Chris Price](http://www.scottlogic.co.uk/blog/chris/). diff --git a/architecture-examples/dart/.bowerrc b/architecture-examples/dart/.bowerrc new file mode 100644 index 0000000000..e0a4aac989 --- /dev/null +++ b/architecture-examples/dart/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "web/bower_components" +} diff --git a/architecture-examples/dart/bower.json b/architecture-examples/dart/bower.json new file mode 100644 index 0000000000..1cab3809ac --- /dev/null +++ b/architecture-examples/dart/bower.json @@ -0,0 +1,7 @@ +{ + "name": "dart", + "version": "0.0.0", + "dependencies": { + "todomvc-common": "~0.1.6" + } +} \ No newline at end of file diff --git a/architecture-examples/dart/readme.md b/architecture-examples/dart/readme.md index 5a73811dbc..0286acdfd1 100644 --- a/architecture-examples/dart/readme.md +++ b/architecture-examples/dart/readme.md @@ -1,10 +1,37 @@ -# Dart • [TodoMVC](http://todomvc.com) +# Dart TodoMVC Example -A TodoMVC sample built with Dart. It does not use a MVC framework - it's a Vanilla Dart sample. +> Dart is a class-based, object-oriented language with lexical scoping, closures, and optional static typing. Dart helps you build structured modern web apps and is easy to learn for a wide range of developers. -Dart firstly targets the development of modern and large scale browser-side web apps. It's an object oriented language with a C-style syntax. +> _[Dart - dartlang.org](http://dartlang.org)_ -## Run + +## Learning Dart + +The [Dart website](http://www.dartlang.org) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Documentation](http://www.dartlang.org/docs/technical-overview) +* [API Reference](http://api.dartlang.org/docs/releases/latest) +* [A Tour of the Dart Language](http://www.dartlang.org/docs/dart-up-and-running/contents/ch02.html) +* [Articles](http://www.dartlang.org/articles) +* [Tutorials](http://www.dartlang.org/docs/tutorials) +* [FAQ](http://www.dartlang.org/support/faq.html) + +Articles and guides from the community: + +* [Getting started with Google Dart](http://www.techrepublic.com/blog/webmaster/getting-started-with-google-dart/931) + +Get help from other Dart users: + +* [Dart on StackOverflow](http://stackoverflow.com/questions/tagged/dart) +* [Dart on Twitter](http://twitter.com/dart_lang) +* [Dart on Google +](https://plus.google.com/+dartlang/posts) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ + + +## Running Dart compiles to JavaScript and thus runs across modern browsers. Dart also can run in its own virtual machine. @@ -12,18 +39,20 @@ Both Dart files and JS compilation result are provided in this sample, therefore To edit and debug the code, you can use Dart Editor. The editor ships with the [SDK](http://dartlang.org) and [Dartium](http://www.dartlang.org/dartium/), a dedicated version of Chromium with an embedded Dart VM. -## How to compile to JS + +## Compiling ``` cd web/dart -dart2js app.dart -oapp.dart.js +dart2js app.dart -oapp.dart.js ``` The dart2js compilator can be found in the SDK. The currently provided JS is minified (dart2js [...] --minify). -## Dart syntax analysis + +## Syntax Analysis ``` cd web/dart @@ -36,6 +65,7 @@ Dart SDK is still under active development, and new releases include breaking ch Build history can be seen [here](https://drone.io/mlorber/todomvc-dart) + ## Credit -Made by [Mathieu Lorber](http://mlorber.net) +This TodoMVC application was created by [Mathieu Lorber](http://mlorber.net). diff --git a/architecture-examples/dart/web/assets/base.js b/architecture-examples/dart/web/assets/base.js deleted file mode 100644 index 9d411e6840..0000000000 --- a/architecture-examples/dart/web/assets/base.js +++ /dev/null @@ -1,40 +0,0 @@ -(function () { - 'use strict'; - - if (location.hostname === 'todomvc.com') { - window._gaq=[['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); - } - - function getSourcePath() { - // If accessed via addyosmani.github.com/todomvc/, strip the project - // path. - if (location.hostname.indexOf('github.com') > 0) { - return location.pathname.replace(/todomvc\//, ''); - } - return location.pathname; - } - - function appendSourceLink() { - var sourceLink = document.createElement('a'); - var paragraph = document.createElement('p'); - var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; - - if (footer) { - sourceLink.href = urlBase + getSourcePath(); - sourceLink.appendChild(document.createTextNode('Check out the source')); - paragraph.appendChild(sourceLink); - footer.appendChild(paragraph); - } - } - - function redirect() { - if (location.hostname === 'addyosmani.github.com') { - location.href = location.href.replace('addyosmani.github.com/todomvc', - 'todomvc.com'); - } - } - - appendSourceLink(); - redirect(); -})(); diff --git a/architecture-examples/dart/web/assets/ie.js b/architecture-examples/dart/web/assets/ie.js deleted file mode 100644 index 82e6a63dcb..0000000000 --- a/architecture-examples/dart/web/assets/ie.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! HTML5 Shiv pre3.5 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed - Uncompressed source: https://github.com/aFarkas/html5shiv */ -(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x";c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^<|^(?:a|b|button|code|div|fieldset|form|h1|h2|h3|h4|h5|h6|i|iframe|img|input|label|li|link|ol|option|p|param|q|script|select|span|strong|style|table|tbody|td|textarea|tfoot|th|thead|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment();for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d>>0;if("[object Function]"!=m(a))throw new TypeError; -for(;c>>0,e=Array(c);if("[object Function]"!=m(a))throw new TypeError;for(var g=0;g>>0,e=[];if("[object Function]"!=m(a))throw new TypeError;for(var g=0;g>>0;if("[object Function]"!=m(a))throw new TypeError;for(var e=0;e>>0;if("[object Function]"!=m(a))throw new TypeError;for(var e=0;e>>0;if("[object Function]"!=m(a))throw new TypeError; -if(!b&&1==arguments.length)throw new TypeError;var c=0,e;if(2<=arguments.length)e=arguments[1];else{do{if(c in d){e=d[c++];break}if(++c>=b)throw new TypeError;}while(1)}for(;c>>0;if("[object Function]"!=m(a))throw new TypeError;if(!b&&1==arguments.length)throw new TypeError;var c,b=b-1;if(2<=arguments.length)c=arguments[1];else{do{if(b in d){c=d[b--]; -break}if(0>--b)throw new TypeError;}while(1)}do b in this&&(c=a.call(void 0,c,d[b],b,d));while(b--);return c};if(!Array.prototype.indexOf)Array.prototype.indexOf=function(a){var d=i(this),b=d.length>>>0;if(!b)return-1;var c=0;1>>0;if(!b)return-1;var c=b-1;1c?"-":9999=c?-4:-6);for(d=a.length;d--;)b=a[d],10>b&&(a[d]="0"+b);return c+"-"+a.slice(0,2).join("-")+"T"+a.slice(2).join(":")+"."+("000"+this.getUTCMilliseconds()).slice(-3)+"Z"};if(!Date.now)Date.now=function(){return(new Date).getTime()};if(!Date.prototype.toJSON)Date.prototype.toJSON=function(){if("function"!=typeof this.toISOString)throw new TypeError;return this.toISOString()}; -if(!Date.parse||864E13!==Date.parse("+275760-09-13T00:00:00.000Z"))Date=function(a){var d=function g(b,d,c,f,h,i,j){var k=arguments.length;return this instanceof a?(k=1==k&&""+b===b?new a(g.parse(b)):7<=k?new a(b,d,c,f,h,i,j):6<=k?new a(b,d,c,f,h,i):5<=k?new a(b,d,c,f,h):4<=k?new a(b,d,c,f):3<=k?new a(b,d,c):2<=k?new a(b,d):1<=k?new a(b):new a,k.constructor=g,k):a.apply(this,arguments)},b=RegExp("^(\\d{4}|[+-]\\d{6})(?:-(\\d{2})(?:-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{3}))?)?(?:Z|(?:([-+])(\\d{2}):(\\d{2})))?)?)?)?$"), -c;for(c in a)d[c]=a[c];d.now=a.now;d.UTC=a.UTC;d.prototype=a.prototype;d.prototype.constructor=d;d.parse=function(d){var c=b.exec(d);if(c){c.shift();for(var f=1;7>f;f++)c[f]=+(c[f]||(3>f?1:0)),1==f&&c[f]--;var h=+c.pop(),i=+c.pop(),j=c.pop(),f=0;if(j){if(23=h?(c[0]=h+400,a.UTC.apply(this,c)+f-126227808E5):a.UTC.apply(this,c)+f}return a.parse.apply(this,arguments)};return d}(Date);j="\t\n\u000b\u000c\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff"; -if(!String.prototype.trim||j.trim()){j="["+j+"]";var A=RegExp("^"+j+j+"*"),B=RegExp(j+j+"*$");String.prototype.trim=function(){return(""+this).replace(A,"").replace(B,"")}}var v=function(a){a=+a;a!==a?a=0:0!==a&&a!==1/0&&a!==-(1/0)&&(a=(0<",">"+this.innerHTML+"<");c.innerHTML="";return a},d=function(a){var b=this.parentNode;if(null===b)throw DOMException.code= -DOMException.NOT_FOUND_ERR,DOMException;for(c.innerHTML=a;a=c.firstChild;)b.insertBefore(a,this);b.removeChild(this)};if(Object.defineProperty){b={get:b,set:d,enumerable:!0,configurable:!0};try{Object.defineProperty(a,"outerHTML",b)}catch(f){-2146823252===f.number&&(b.enumerable=!1,Object.defineProperty(a,"outerHTML",b))}}else Object.prototype.__defineGetter__&&Object.prototype.__defineSetter__&&(a.__defineGetter__("outerHTML",b),a.__defineSetter__("outerHTML",d))}(self); \ No newline at end of file diff --git a/template/components/todomvc-common/base.css b/architecture-examples/dart/web/bower_components/todomvc-common/base.css similarity index 80% rename from template/components/todomvc-common/base.css rename to architecture-examples/dart/web/bower_components/todomvc-common/base.css index 8d1db3a696..3e6bfaf38d 100644 --- a/template/components/todomvc-common/base.css +++ b/architecture-examples/dart/web/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -412,3 +412,144 @@ label[for='toggle-all'] { .hidden{ display:none; } + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/architecture-examples/dart/web/bower_components/todomvc-common/base.js b/architecture-examples/dart/web/bower_components/todomvc-common/base.js new file mode 100644 index 0000000000..099da60dd1 --- /dev/null +++ b/architecture-examples/dart/web/bower_components/todomvc-common/base.js @@ -0,0 +1,209 @@ +(function () { + 'use strict'; + + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + + if (location.hostname === 'todomvc.com') { + window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); + } + + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); + } + } + + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } + + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); + } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; + } + + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); + } + } + + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + + redirect(); + getFile('learn.json', Learn); +})(); diff --git a/architecture-examples/dart/web/assets/bg.png b/architecture-examples/dart/web/bower_components/todomvc-common/bg.png similarity index 100% rename from architecture-examples/dart/web/assets/bg.png rename to architecture-examples/dart/web/bower_components/todomvc-common/bg.png diff --git a/architecture-examples/dart/web/index.html b/architecture-examples/dart/web/index.html index fd25cb84eb..b1429444d8 100644 --- a/architecture-examples/dart/web/index.html +++ b/architecture-examples/dart/web/index.html @@ -1,48 +1,45 @@ - - - - - Dart • TodoMVC - - - - -
- -
- - -
    + + + + + Dart • TodoMVC + + + +
    + +
    + + +
      +
      +
      -
      - - - - - + + + + diff --git a/architecture-examples/dojo/bower.json b/architecture-examples/dojo/bower.json new file mode 100644 index 0000000000..e049881286 --- /dev/null +++ b/architecture-examples/dojo/bower.json @@ -0,0 +1,7 @@ +{ + "name": "todmvc-dojo", + "version": "0.0.0", + "dependencies": { + "todomvc-common": "~0.1.6" + } +} diff --git a/labs/dependency-examples/troopjs/bower_components/todomvc-common/base.css b/architecture-examples/dojo/bower_components/todomvc-common/base.css similarity index 80% rename from labs/dependency-examples/troopjs/bower_components/todomvc-common/base.css rename to architecture-examples/dojo/bower_components/todomvc-common/base.css index 8d1db3a696..3e6bfaf38d 100644 --- a/labs/dependency-examples/troopjs/bower_components/todomvc-common/base.css +++ b/architecture-examples/dojo/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -412,3 +412,144 @@ label[for='toggle-all'] { .hidden{ display:none; } + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/architecture-examples/dojo/bower_components/todomvc-common/base.js b/architecture-examples/dojo/bower_components/todomvc-common/base.js new file mode 100644 index 0000000000..099da60dd1 --- /dev/null +++ b/architecture-examples/dojo/bower_components/todomvc-common/base.js @@ -0,0 +1,209 @@ +(function () { + 'use strict'; + + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + + if (location.hostname === 'todomvc.com') { + window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); + } + + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); + } + } + + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } + + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); + } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; + } + + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); + } + } + + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + + redirect(); + getFile('learn.json', Learn); +})(); diff --git a/labs/architecture-examples/duel/src/main/webapp/css/bg.png b/architecture-examples/dojo/bower_components/todomvc-common/bg.png similarity index 100% rename from labs/architecture-examples/duel/src/main/webapp/css/bg.png rename to architecture-examples/dojo/bower_components/todomvc-common/bg.png diff --git a/architecture-examples/dojo/index-1.7.html b/architecture-examples/dojo/index-1.7.html index a454b3014a..5f710aa6a5 100644 --- a/architecture-examples/dojo/index-1.7.html +++ b/architecture-examples/dojo/index-1.7.html @@ -1,25 +1,21 @@ - + - + Dojo • TodoMVC - - + - -
      +
      +
      - - + diff --git a/architecture-examples/dojo/index.html b/architecture-examples/dojo/index.html index a27bed088d..7bd063443c 100644 --- a/architecture-examples/dojo/index.html +++ b/architecture-examples/dojo/index.html @@ -1,51 +1,33 @@ - - - - - Dojo • TodoMVC - - - - - - -
      - + + + + + Dojo • TodoMVC + + + + +
      + - - - - + + + + diff --git a/architecture-examples/dojo/readme.md b/architecture-examples/dojo/readme.md index e50d132b15..ef02dbabe0 100644 --- a/architecture-examples/dojo/readme.md +++ b/architecture-examples/dojo/readme.md @@ -1,24 +1,53 @@ -# Dojo TodoMVC app +# Dojo TodoMVC Example -## Building +> Dojo saves you time and scales with your development process, using web standards as its platform. It’s the toolkit experienced developers turn to for building high quality desktop and mobile web applications. + +> _[Dojo - dojotoolkit.org](http://dojotoolkit.org)_ + + +## Learning Dojo + +The [Dojo website](http://dojotoolkit.org) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Documentation](http://dojotoolkit.org/documentation) +* [Getting started guide](https://dojotoolkit.org/reference-guide/1.8/quickstart) +* [API Reference](http://dojotoolkit.org/api) +* [Blog](http://dojotoolkit.org/blog) + +Articles and guides from the community: + +* [Getting StartED with Dojo](http://startdojo.com) + +Get help from other Dojo users: + +* [Dojo on StackOverflow](http://stackoverflow.com/questions/tagged/dojo) +* [Mailing list](http://dojotoolkit.org/community) +* [Dojo on Twitter](http://twitter.com/dojo) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ + + +## Running To build the Dojo app, you first need to download and extract the [Dojo SDK](https://dojotoolkit.org/download/#sdk). At the root folder of the extracted SDK, copy or symlink the complete `todomvc` folder, so your directory structure looks like this: - dojo-release/ - ├── dijit - ├── dojo - ├── dojox - ├── todomvc - └── util + dojo-release/ + ├── dijit + ├── dojo + ├── dojox + ├── todomvc + └── util -Enter the `dojo-release/util` folder and run these commands to build the -`dojo.js` file including all required resources and copy it back into the -todomvc folder. You need either java or node on your system to run these: +Enter the `dojo-release/util` folder and run these commands to build the `dojo.js` file including all required resources and copy it back into the todomvc folder. You need either java or node on your system to run these: - buildscripts/build.sh --profile ../todomvc/architecture-examples/dojo/profiles/todomvc.profile.js -r - cp ../release/dojo/dojo/dojo.js ../todomvc/architecture-examples/dojo/js/lib/dojo-1.8/dojo.js +``` +buildscripts/build.sh --profile ../todomvc/architecture-examples/dojo/profiles/todomvc.profile.js -r +cp ../release/dojo/dojo/dojo.js ../todomvc/architecture-examples/dojo/js/lib/dojo-1.8/dojo.js +``` After a new release of Dojo, you may need to copy more files for this to work. Check out the `js/lib/` folder for other files that are required from the diff --git a/architecture-examples/emberjs/bower_components/todomvc-common/base.css b/architecture-examples/emberjs/bower_components/todomvc-common/base.css index 8d1db3a696..3e6bfaf38d 100644 --- a/architecture-examples/emberjs/bower_components/todomvc-common/base.css +++ b/architecture-examples/emberjs/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -412,3 +412,144 @@ label[for='toggle-all'] { .hidden{ display:none; } + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/architecture-examples/emberjs/bower_components/todomvc-common/base.js b/architecture-examples/emberjs/bower_components/todomvc-common/base.js index 3fd166d061..099da60dd1 100644 --- a/architecture-examples/emberjs/bower_components/todomvc-common/base.js +++ b/architecture-examples/emberjs/bower_components/todomvc-common/base.js @@ -1,38 +1,209 @@ (function () { 'use strict'; + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + if (location.hostname === 'todomvc.com') { window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); } - function getSourcePath() { - // If accessed via addyosmani.github.io/todomvc/, strip the project path. - if (location.hostname.indexOf('github.io') > 0) { - return location.pathname.replace(/todomvc\//, ''); + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); } - return location.pathname; } - function appendSourceLink() { - var sourceLink = document.createElement('a'); - var paragraph = document.createElement('p'); - var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } - if (footer) { - sourceLink.href = urlBase + getSourcePath(); - sourceLink.appendChild(document.createTextNode('Check out the source')); - paragraph.appendChild(sourceLink); - footer.appendChild(paragraph); + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; } - function redirect() { - if (location.hostname === 'addyosmani.github.io') { - location.href = location.href.replace('addyosmani.github.io/todomvc', 'todomvc.com'); + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); } } - appendSourceLink(); + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + redirect(); + getFile('learn.json', Learn); })(); diff --git a/architecture-examples/emberjs/index.html b/architecture-examples/emberjs/index.html index ceafb7461b..b06172537f 100644 --- a/architecture-examples/emberjs/index.html +++ b/architecture-examples/emberjs/index.html @@ -1,8 +1,8 @@ - + - + ember.js • TodoMVC diff --git a/architecture-examples/emberjs/js/libs/ember-data.js b/architecture-examples/emberjs/js/libs/ember-data.js index 6db1c0fd51..d6d9ca2078 100644 --- a/architecture-examples/emberjs/js/libs/ember-data.js +++ b/architecture-examples/emberjs/js/libs/ember-data.js @@ -1,7 +1,10 @@ +// Last commit: 2bcc767 (2013-03-07 17:07:46 -0800) + + (function() { window.DS = Ember.Namespace.create({ - // this one goes to 11 - CURRENT_API_REVISION: 11 + // this one goes past 11 + CURRENT_API_REVISION: 12 }); })(); @@ -846,7 +849,7 @@ DS._Mappable = Ember.Mixin.create({ instanceMap.set(transformedKey, newValue); } - }, + } }); @@ -2268,7 +2271,6 @@ DS.Store = Ember.Object.extend(DS._Mappable, { } var content = get(array, 'content'); - var alreadyInArray = content.indexOf(clientId) !== -1; var recordArrays = this.recordArraysForClientId(clientId); var reference = this.referenceForClientId(clientId); @@ -2413,7 +2415,6 @@ DS.Store = Ember.Object.extend(DS._Mappable, { if (prematerialized && prematerialized.id) { id = prematerialized.id; } else if (id === undefined) { - var adapter = this.adapterForType(type); id = this.preprocessData(type, data); } @@ -2492,6 +2493,8 @@ DS.Store = Ember.Object.extend(DS._Mappable, { clientIds = typeMap.clientIds, cidToData = this.clientIdToData; + Ember.assert('The id ' + id + ' has already been used with another record of type ' + type.toString() + '.', !id || !idToClientIdMap[id]); + var clientId = ++this.clientIdCounter; cidToData[clientId] = data; @@ -2518,7 +2521,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { this.recordCache[clientId] = record = type._create({ store: this, - clientId: clientId, + clientId: clientId }); set(record, 'id', id); @@ -2546,12 +2549,10 @@ DS.Store = Ember.Object.extend(DS._Mappable, { if (id) { delete typeMap.idToCid[id]; } }, - destroy: function() { + willDestroy: function() { if (get(DS, 'defaultStore') === this) { set(DS, 'defaultStore', null); } - - return this._super(); }, // ........................ @@ -3835,6 +3836,7 @@ var storeAlias = function(methodName) { args = [].slice.call(arguments); args.unshift(this); + Ember.assert("Your application does not have a 'Store' property defined. Attempts to call '" + methodName + "' on model classes will fail. Please provide one as with 'YourAppName.Store = DS.Store.extend()'", !!store); return store[methodName].apply(store, args); }; }; @@ -3843,6 +3845,7 @@ DS.Model.reopenClass({ isLoaded: storeAlias('recordIsLoaded'), find: storeAlias('find'), all: storeAlias('all'), + query: storeAlias('findQuery'), filter: storeAlias('filter'), _create: DS.Model.create, @@ -4180,7 +4183,6 @@ DS.Model.reopenClass({ App.Blog = DS.Model.extend({ users: DS.hasMany(App.User), owner: DS.belongsTo(App.User), - posts: DS.hasMany(App.Post) }); @@ -4256,6 +4258,51 @@ DS.Model.reopenClass({ return names; }), + /** + An array of types directly related to a model. Each type will be + included once, regardless of the number of relationships it has with + the model. + + For example, given a model with this definition: + + App.Blog = DS.Model.extend({ + users: DS.hasMany(App.User), + owner: DS.belongsTo(App.User), + posts: DS.hasMany(App.Post) + }); + + This property would contain the following: + + var relatedTypes = Ember.get(App.Blog, 'relatedTypes'); + //=> [ App.User, App.Post ] + + @type Ember.Array + @readOnly + */ + relatedTypes: Ember.computed(function() { + var type, + types = Ember.A([]); + + // Loop through each computed property on the class, + // and create an array of the unique types involved + // in relationships + this.eachComputedProperty(function(name, meta) { + if (meta.isRelationship) { + type = meta.type; + + if (typeof type === 'string') { + type = get(this, type, false) || get(Ember.lookup, type); + } + + if (!types.contains(type)) { + types.push(type); + } + } + }); + + return types; + }), + /** A map whose keys are the relationships of a model and whose values are relationship descriptors. @@ -4357,6 +4404,21 @@ DS.Model.reopenClass({ get(this, 'relationshipsByName').forEach(function(name, relationship) { callback.call(binding, name, relationship); }); + }, + + /** + Given a callback, iterates over each of the types related to a model, + invoking the callback with the related type's class. Each type will be + returned just once, regardless of how many different relationships it has + with a model. + + @param {Function} callback the callback to invoke + @param {any} binding the value to which the callback's `this` should be bound + */ + eachRelatedType: function(callback, binding) { + get(this, 'relatedTypes').forEach(function(type) { + callback.call(binding, type); + }); } }); @@ -4447,6 +4509,8 @@ var get = Ember.get, set = Ember.set; var forEach = Ember.EnumerableUtils.forEach; DS.RelationshipChange = function(options) { + this.parentReference = options.parentReference; + this.childReference = options.childReference; this.firstRecordReference = options.firstRecordReference; this.firstRecordKind = options.firstRecordKind; this.firstRecordName = options.firstRecordName; @@ -4502,7 +4566,7 @@ DS.RelationshipChange.determineRelationshipType = function(recordType, knownSide var knownContainerType = knownSide.kind; var options = recordType.metaForProperty(knownKey).options; var otherType = DS._inverseTypeFor(recordType, knownKey); - + if(options.inverse){ key = options.inverse; otherContainerType = get(otherType, 'relationshipsByName').get(key).kind; @@ -4536,10 +4600,10 @@ DS.RelationshipChange.createChange = function(firstRecordReference, secondRecord return DS.OneToManyChange.createChange(secondRecordReference, firstRecordReference, store, options); } else if (changeType === "oneToNone"){ - return DS.OneToNoneChange.createChange(firstRecordReference, {}, store, options); + return DS.OneToNoneChange.createChange(firstRecordReference, secondRecordReference, store, options); } else if (changeType === "manyToNone"){ - return DS.ManyToNoneChange.createChange(firstRecordReference, {}, store, options); + return DS.ManyToNoneChange.createChange(firstRecordReference, secondRecordReference, store, options); } else if (changeType === "oneToOne"){ return DS.OneToOneChange.createChange(firstRecordReference, secondRecordReference, store, options); @@ -4553,6 +4617,8 @@ DS.RelationshipChange.createChange = function(firstRecordReference, secondRecord DS.OneToNoneChange.createChange = function(childReference, parentReference, store, options) { var key = options.key; var change = DS.RelationshipChange._createChange({ + parentReference: parentReference, + childReference: childReference, firstRecordReference: childReference, store: store, changeType: options.changeType, @@ -4563,12 +4629,14 @@ DS.OneToNoneChange.createChange = function(childReference, parentReference, stor store.addRelationshipChangeFor(childReference, key, parentReference, null, change); return change; -}; +}; /** @private */ DS.ManyToNoneChange.createChange = function(childReference, parentReference, store, options) { var key = options.key; var change = DS.RelationshipChange._createChange({ + parentReference: childReference, + childReference: parentReference, secondRecordReference: childReference, store: store, changeType: options.changeType, @@ -4578,14 +4646,14 @@ DS.ManyToNoneChange.createChange = function(childReference, parentReference, sto store.addRelationshipChangeFor(childReference, key, parentReference, null, change); return change; -}; +}; /** @private */ DS.ManyToManyChange.createChange = function(childReference, parentReference, store, options) { // Get the type of the child based on the child's client ID var childType = childReference.type, key; - + // If the name of the belongsTo side of the relationship is specified, // use that // If the type of the parent is specified, look it up on the child's type @@ -4593,6 +4661,8 @@ DS.ManyToManyChange.createChange = function(childReference, parentReference, sto key = options.key; var change = DS.RelationshipChange._createChange({ + parentReference: parentReference, + childReference: childReference, firstRecordReference: childReference, secondRecordReference: parentReference, firstRecordKind: "hasMany", @@ -4612,7 +4682,7 @@ DS.ManyToManyChange.createChange = function(childReference, parentReference, sto DS.OneToOneChange.createChange = function(childReference, parentReference, store, options) { // Get the type of the child based on the child's client ID var childType = childReference.type, key; - + // If the name of the belongsTo side of the relationship is specified, // use that // If the type of the parent is specified, look it up on the child's type @@ -4627,6 +4697,8 @@ DS.OneToOneChange.createChange = function(childReference, parentReference, store } var change = DS.RelationshipChange._createChange({ + parentReference: parentReference, + childReference: childReference, firstRecordReference: childReference, secondRecordReference: parentReference, firstRecordKind: "belongsTo", @@ -4663,7 +4735,7 @@ DS.OneToOneChange.maintainInvariant = function(options, store, childReference, k DS.OneToManyChange.createChange = function(childReference, parentReference, store, options) { // Get the type of the child based on the child's client ID var childType = childReference.type, key; - + // If the name of the belongsTo side of the relationship is specified, // use that // If the type of the parent is specified, look it up on the child's type @@ -4678,6 +4750,8 @@ DS.OneToManyChange.createChange = function(childReference, parentReference, stor } var change = DS.RelationshipChange._createChange({ + parentReference: parentReference, + childReference: childReference, firstRecordReference: childReference, secondRecordReference: parentReference, firstRecordKind: "belongsTo", @@ -4764,13 +4838,13 @@ DS.RelationshipChange.prototype = { /** @private */ destroy: function() { - var childReference = this.firstRecordReference, + var childReference = this.childReference, belongsToName = this.getFirstRecordName(), hasManyName = this.getSecondRecordName(), store = this.store, child, oldParent, newParent, lastParent, transaction; - store.removeRelationshipChangeFor(childReference, belongsToName, this.secondRecordReference, hasManyName, this.changeType); + store.removeRelationshipChangeFor(childReference, belongsToName, this.parentReference, hasManyName, this.changeType); if (transaction = this.transaction) { transaction.relationshipBecameClean(this); @@ -4920,7 +4994,9 @@ DS.RelationshipChangeRemove.prototype.sync = function() { if (secondRecord && firstRecord) { if(this.secondRecordKind === "belongsTo"){ + secondRecord.suspendRelationshipObservers(function(){ set(secondRecord, secondRecordName, null); + }); } else if(this.secondRecordKind === "hasMany"){ secondRecord.suspendRelationshipObservers(function(){ @@ -5608,7 +5684,7 @@ DS.Serializer = Ember.Object.extend({ primaryKey: function(type) { // If the type is `BlogPost`, this will return // `blog_post_id`. - var typeString = type.toString.split(".")[1].underscore(); + var typeString = type.toString().split(".")[1].underscore(); return typeString + "_id"; } }); @@ -5986,10 +6062,10 @@ DS.Serializer = Ember.Object.extend({ registerEnumTransform: function(type, objects) { var transform = { deserialize: function(deserialized) { - return objects.objectAt(deserialized); + return Ember.A(objects).objectAt(deserialized); }, serialize: function(serialized) { - return objects.indexOf(serialized); + return Ember.EnumerableUtils.indexOf(objects, serialized); }, values: objects }; @@ -6283,6 +6359,13 @@ DS.JSONSerializer = DS.Serializer.extend({ if (sideloadAs) { this.sideloadMapping.set(sideloadAs, type); + + // Set a flag indicating that mappings may need to be normalized + // (i.e. converted from strings -> types) before sideloading. + // We can't do this conversion immediately here, because `configure` + // may be called before certain types have been defined. + this.sideloadMapping.normalized = false; + delete configuration.sideloadAs; } @@ -6352,7 +6435,7 @@ DS.JSONSerializer = DS.Serializer.extend({ if (this.embeddedType(type, name)) { if (embeddedChild = get(record, name)) { - value = this.serialize(embeddedChild, { include: true }); + value = this.serialize(embeddedChild, { includeId: true }); } hash[key] = value; @@ -6444,46 +6527,88 @@ DS.JSONSerializer = DS.Serializer.extend({ } }, + /** + @private + + Iterates over the `json` payload and attempts to load any data + included alongside `root`. + + The keys expected for sideloaded data are based upon the types related + to the root model. Recursion is used to ensure that types related to + related types can be loaded as well. Any custom keys specified by + `sideloadAs` mappings will also be respected. + + @param {DS.Store subclass} loader + @param {DS.Model subclass} type + @param {Object} json + @param {String} root + */ sideload: function(loader, type, json, root) { - var sideloadedType, mappings, loaded = {}; + var sideloadedType; - loaded[root] = true; + this.normalizeSideloadMappings(); + this.configureSideloadMappingForType(type); for (var prop in json) { - if (!json.hasOwnProperty(prop)) { continue; } - if (prop === root) { continue; } - if (prop === this.configOption(type, 'meta')) { continue; } + if (!json.hasOwnProperty(prop) || + prop === root || + prop === this.configOption(type, 'meta')) { + continue; + } - sideloadedType = type.typeForRelationship(prop); + sideloadedType = this.sideloadMapping.get(prop); + Ember.assert("Your server returned a hash with the key " + prop + + " but you have no mapping for it", + !!sideloadedType); - if (!sideloadedType) { - sideloadedType = this.sideloadMapping.get(prop); + this.loadValue(loader, sideloadedType, json[prop]); + } + }, - if (typeof sideloadedType === 'string') { - sideloadedType = get(Ember.lookup, sideloadedType); - } + /** + @private - Ember.assert("Your server returned a hash with the key " + prop + " but you have no mapping for it", !!sideloadedType); - } + Iterates over all the `sideloadAs` mappings and converts any that are + strings to their equivalent types. - this.sideloadRelationships(loader, sideloadedType, json, prop, loaded); + This is an optimization used to avoid performing lookups for every + call to `sideload`. + */ + normalizeSideloadMappings: function() { + if (! this.sideloadMapping.normalized) { + this.sideloadMapping.forEach(function(key, value) { + if (typeof value === 'string') { + this.sideloadMapping.set(key, get(Ember.lookup, value)); + } + }, this); + this.sideloadMapping.normalized = true; } }, - sideloadRelationships: function(loader, type, json, prop, loaded) { - loaded[prop] = true; + /** + @private - get(type, 'relationshipsByName').forEach(function(key, meta) { - key = meta.key || key; - if (meta.kind === 'belongsTo') { - key = this.pluralize(key); - } - if (json[key] && !loaded[key]) { - this.sideloadRelationships(loader, meta.type, json, key, loaded); + Configures possible sideload mappings for the types related to a + particular model. This recursive method ensures that sideloading + works for related models as well. + + @param {DS.Model subclass} type + @param {Ember.A} configured an array of types that have already been configured + */ + configureSideloadMappingForType: function(type, configured) { + if (!configured) {configured = Ember.A([]);} + configured.pushObject(type); + + type.eachRelatedType(function(relatedType) { + if (!configured.contains(relatedType)) { + var root = this.sideloadMappingForType(relatedType); + if (!root) { + root = this.defaultSideloadRootForType(relatedType); + this.sideloadMapping.set(root, relatedType); + } + this.configureSideloadMappingForType(relatedType, configured); } }, this); - - this.loadValue(loader, type, json[prop]); }, loadValue: function(loader, type, value) { @@ -6505,6 +6630,36 @@ DS.JSONSerializer = DS.Serializer.extend({ return (plurals && plurals[name]) || name + "s"; }, + // use the same plurals hash to determine + // special-case singularization + singularize: function(name) { + var plurals = this.configurations.get('plurals'); + if (plurals) { + for (var i in plurals) { + if (plurals[i] === name) { + return i; + } + } + } + if (name.lastIndexOf('s') === name.length - 1) { + return name.substring(0, name.length - 1); + } else { + return name; + } + }, + + /** + @private + + Determines the singular root name for a particular type. + + This is an underscored, lowercase version of the model name. + For example, the type `App.UserGroup` will have the root + `user_group`. + + @param {DS.Model subclass} type + @returns {String} name of the root element + */ rootForType: function(type) { var typeString = type.toString(); @@ -6514,6 +6669,34 @@ DS.JSONSerializer = DS.Serializer.extend({ var parts = typeString.split("."); var name = parts[parts.length - 1]; return name.replace(/([A-Z])/g, '_$1').toLowerCase().slice(1); + }, + + /** + @private + + Determines the root name mapped to a particular sideloaded type. + + @param {DS.Model subclass} type + @returns {String} name of the root element, if any is registered + */ + sideloadMappingForType: function(type) { + this.sideloadMapping.forEach(function(key, value) { + if (type === value) { + return key; + } + }); + }, + + /** + @private + + The default root name for a particular sideloaded type. + + @param {DS.Model subclass} type + @returns {String} name of the root element + */ + defaultSideloadRootForType: function(type) { + return this.pluralize(this.rootForType(type)); } }); @@ -6685,7 +6868,6 @@ DS.Adapter = Ember.Object.extend(DS._Mappable, { if (payload) { var loader = DS.loaderFor(store); - var serializer = get(this, 'serializer'); loader.load = function(type, data, prematerialized) { store.updateId(record, data); @@ -7236,14 +7418,121 @@ DS.Adapter.reopenClass({ (function() { -var get = Ember.get; +var get = Ember.get, set = Ember.set; + +DS.FixtureSerializer = DS.Serializer.extend({ + deserializeValue: function(value, attributeType) { + return value; + }, + + serializeValue: function(value, attributeType) { + return value; + }, + + addId: function(data, key, id) { + data[key] = id; + }, + addAttribute: function(hash, key, value) { + hash[key] = value; + }, + + addBelongsTo: function(hash, record, key, relationship) { + var id = get(record, relationship.key+'.id'); + if (!Ember.isNone(id)) { hash[key] = id; } + }, + + addHasMany: function(hash, record, key, relationship) { + var ids = get(record, relationship.key).map(function(item) { + return item.get('id'); + }); + + hash[relationship.key] = ids; + }, + + /** + @private + + Creates an empty hash that will be filled in by the hooks called from the + `serialize()` method. + + @return {Object} + */ + createSerializedForm: function() { + return {}; + }, + + extract: function(loader, fixture, type, record) { + if (record) { loader.updateId(record, fixture); } + this.extractRecordRepresentation(loader, type, fixture); + }, + + extractMany: function(loader, fixtures, type, records) { + var objects = fixtures, references = []; + if (records) { records = records.toArray(); } + + for (var i = 0; i < objects.length; i++) { + if (records) { loader.updateId(records[i], objects[i]); } + var reference = this.extractRecordRepresentation(loader, type, objects[i]); + references.push(reference); + } + + loader.populateArray(references); + }, + + extractId: function(type, hash) { + var primaryKey = this._primaryKey(type); + + if (hash.hasOwnProperty(primaryKey)) { + // Ensure that we coerce IDs to strings so that record + // IDs remain consistent between application runs; especially + // if the ID is serialized and later deserialized from the URL, + // when type information will have been lost. + return hash[primaryKey]+''; + } else { + return null; + } + }, + + extractAttribute: function(type, hash, attributeName) { + var key = this._keyForAttributeName(type, attributeName); + return hash[key]; + }, + + extractHasMany: function(type, hash, key) { + return hash[key]; + }, + + extractBelongsTo: function(type, hash, key) { + return hash[key]; + } +}); + +})(); + + + +(function() { +var get = Ember.get, fmt = Ember.String.fmt; + +/** + `DS.FixtureAdapter` is an adapter that loads records from memory. + Its primarily used for development and testing. You can also use + `DS.FixtureAdapter` while working on the API but are not ready to + integrate yet. It is a fully functioning adapter. All CRUD methods + are implemented. You can also implement query logic that a remote + system would do. Its possible to do develop your entire application + with `DS.FixtureAdapter`. + +*/ DS.FixtureAdapter = DS.Adapter.extend({ simulateRemoteResponse: true, latency: 50, + serializer: DS.FixtureSerializer, + /* Implement this method in order to provide data associated with a type */ @@ -7252,7 +7541,7 @@ DS.FixtureAdapter = DS.Adapter.extend({ var fixtures = Ember.A(type.FIXTURES); return fixtures.map(function(fixture){ if(!fixture.id){ - throw new Error('the id property must be defined for fixture %@'.fmt(fixture)); + throw new Error(fmt('the id property must be defined for fixture %@', [fixture])); } fixture.id = fixture.id + ''; return fixture; @@ -7265,7 +7554,19 @@ DS.FixtureAdapter = DS.Adapter.extend({ Implement this method in order to query fixtures data */ queryFixtures: function(fixtures, query, type) { - return fixtures; + Ember.assert('Not implemented: You must override the DS.FixtureAdapter::queryFixtures method to support querying the fixture store.'); + }, + + updateFixtures: function(type, fixture) { + if(!type.FIXTURES) { + type.FIXTURES = []; + } + + var fixtures = type.FIXTURES; + + this.deleteLoadedFixture(type, fixture); + + fixtures.push(fixture); }, /* @@ -7283,18 +7584,19 @@ DS.FixtureAdapter = DS.Adapter.extend({ }, find: function(store, type, id) { - var fixtures = this.fixturesForType(type); + var fixtures = this.fixturesForType(type), + fixture; - Ember.assert("Unable to find fixtures for model type "+type.toString(), !!fixtures); + Ember.warn("Unable to find fixtures for model type " + type.toString(), fixtures); if (fixtures) { - fixtures = fixtures.findProperty('id', id); + fixture = Ember.A(fixtures).findProperty('id', id); } - if (fixtures) { + if (fixture) { this.simulateRemoteCall(function() { - store.load(type, fixtures); - }, store, type); + this.didFindRecord(store, type, fixture, id); + }, this); } }, @@ -7311,8 +7613,8 @@ DS.FixtureAdapter = DS.Adapter.extend({ if (fixtures) { this.simulateRemoteCall(function() { - store.loadMany(type, fixtures); - }, store, type); + this.didFindMany(store, type, fixtures); + }, this); } }, @@ -7322,9 +7624,8 @@ DS.FixtureAdapter = DS.Adapter.extend({ Ember.assert("Unable to find fixtures for model type "+type.toString(), !!fixtures); this.simulateRemoteCall(function() { - store.loadMany(type, fixtures); - store.didUpdateAll(type); - }, store, type); + this.didFindAll(store, type, fixtures); + }, this); }, findQuery: function(store, type, query, array) { @@ -7336,43 +7637,82 @@ DS.FixtureAdapter = DS.Adapter.extend({ if (fixtures) { this.simulateRemoteCall(function() { - array.load(fixtures); - }, store, type); + this.didFindQuery(store, type, fixtures, array); + }, this); } }, createRecord: function(store, type, record) { var fixture = this.mockJSON(type, record); - fixture.id = this.generateIdForRecord(store, record); + this.updateFixtures(type, fixture); this.simulateRemoteCall(function() { - store.didSaveRecord(record, fixture); - }, store, type, record); + this.didCreateRecord(store, type, record, fixture); + }, this); }, updateRecord: function(store, type, record) { var fixture = this.mockJSON(type, record); + this.updateFixtures(type, fixture); + this.simulateRemoteCall(function() { - store.didSaveRecord(record, fixture); - }, store, type, record); + this.didUpdateRecord(store, type, record, fixture); + }, this); }, deleteRecord: function(store, type, record) { + var fixture = this.mockJSON(type, record); + + this.deleteLoadedFixture(type, fixture); + this.simulateRemoteCall(function() { - store.didSaveRecord(record); - }, store, type, record); + this.didDeleteRecord(store, type, record); + }, this); }, /* @private */ - simulateRemoteCall: function(callback, store, type, record) { + deleteLoadedFixture: function(type, record) { + var id = this.extractId(type, record); + + var existingFixture = this.findExistingFixture(type, record); + + if(existingFixture) { + var index = type.FIXTURES.indexOf(existingFixture); + type.FIXTURES.splice(index, 1); + return true; + } + }, + + findExistingFixture: function(type, record) { + var fixtures = this.fixturesForType(type); + var id = this.extractId(type, record); + + return this.findFixtureById(fixtures, id); + }, + + findFixtureById: function(fixtures, id) { + var adapter = this; + + return Ember.A(fixtures).find(function(r) { + if(''+get(r, 'id') === ''+id) { + return true; + } else { + return false; + } + }); + }, + + simulateRemoteCall: function(callback, context) { if (get(this, 'simulateRemoteResponse')) { - setTimeout(callback, get(this, 'latency')); + // Schedule with setTimeout + Ember.run.later(context, callback, get(this, 'latency')); } else { - callback(); + // Asynchronous, but at the of the runloop with zero latency + Ember.run.once(context, callback); } } }); @@ -7395,6 +7735,16 @@ DS.RESTSerializer = DS.JSONSerializer.extend({ } return key + "_id"; + }, + + keyForHasMany: function(type, name) { + var key = this.keyForAttributeName(type, name); + + if (this.embeddedType(type, name)) { + return key; + } + + return this.singularize(key) + "_ids"; } }); @@ -7499,12 +7849,25 @@ DS.RESTAdapter = DS.Adapter.extend({ }, dirtyRecordsForRecordChange: function(dirtySet, record) { + this._dirtyTree(dirtySet, record); + }, + + dirtyRecordsForHasManyChange: function(dirtySet, record, relationship) { + var embeddedType = get(this, 'serializer').embeddedType(record.constructor, relationship.secondRecordName); + + if (embeddedType === 'always') { + relationship.childReference.parent = relationship.parentReference; + this._dirtyTree(dirtySet, record); + } + }, + + _dirtyTree: function(dirtySet, record) { dirtySet.add(record); get(this, 'serializer').eachEmbeddedRecord(record, function(embeddedRecord, embeddedType) { if (embeddedType !== 'always') { return; } if (dirtySet.has(embeddedRecord)) { return; } - this.dirtyRecordsForRecordChange(dirtySet, embeddedRecord); + this._dirtyTree(dirtySet, embeddedRecord); }, this); var reference = record.get('_reference'); @@ -7512,12 +7875,10 @@ DS.RESTAdapter = DS.Adapter.extend({ if (reference.parent) { var store = get(record, 'store'); var parent = store.recordForReference(reference.parent); - this.dirtyRecordsForRecordChange(dirtySet, parent); + this._dirtyTree(dirtySet, parent); } }, - dirtyRecordsForHasManyChange: Ember.K, - createRecords: function(store, type, records) { if (get(this, 'bulkCommit') === false) { return this._super(store, type, records); @@ -7762,6 +8123,168 @@ DS.RESTAdapter = DS.Adapter.extend({ +(function() { +var camelize = Ember.String.camelize, + get = Ember.get, + registeredTransforms; + +var passthruTransform = { + serialize: function(value) { return value; }, + deserialize: function(value) { return value; } +}; + +var defaultTransforms = { + string: passthruTransform, + boolean: passthruTransform, + number: passthruTransform +}; + +function camelizeKeys(json) { + var value; + + for (var prop in json) { + value = json[prop]; + delete json[prop]; + json[camelize(prop)] = value; + } +} + +function munge(json, callback) { + callback(json); +} + +function applyTransforms(json, type, transformType) { + var transforms = registeredTransforms[transformType]; + + Ember.assert("You are trying to apply the '" + transformType + "' transforms, but you didn't register any transforms with that name", transforms); + + get(type, 'attributes').forEach(function(name, attribute) { + var attributeType = attribute.type, + value = json[name]; + + var transform = transforms[attributeType] || defaultTransforms[attributeType]; + + Ember.assert("Your model specified the '" + attributeType + "' type for the '" + name + "' attribute, but no transform for that type was registered", transform); + + json[name] = transform.deserialize(value); + }); +} + +function ObjectProcessor(json, type, store) { + this.json = json; + this.type = type; + this.store = store; +} + +ObjectProcessor.prototype = { + load: function() { + this.store.load(this.type, {}, this.json); + }, + + camelizeKeys: function() { + camelizeKeys(this.json); + return this; + }, + + munge: function(callback) { + munge(this.json, callback); + return this; + }, + + applyTransforms: function(transformType) { + applyTransforms(this.json, this.type, transformType); + return this; + } +}; + +function processorFactory(store, type) { + return function(json) { + return new ObjectProcessor(json, type, store); + }; +} + +function ArrayProcessor(json, type, array, store) { + this.json = json; + this.type = type; + this.array = array; + this.store = store; +} + +ArrayProcessor.prototype = { + load: function() { + var store = this.store, + type = this.type; + + var references = this.json.map(function(object) { + return store.load(type, {}, object); + }); + + this.array.load(references); + }, + + camelizeKeys: function() { + this.json.forEach(camelizeKeys); + return this; + }, + + munge: function(callback) { + this.json.forEach(function(object) { + munge(object, callback); + }); + return this; + }, + + applyTransforms: function(transformType) { + var type = this.type; + + this.json.forEach(function(object) { + applyTransforms(object, type, transformType); + }); + + return this; + } +}; + +function arrayProcessorFactory(store, type, array) { + return function(json) { + return new ArrayProcessor(json, type, array, store); + }; +} + +DS.BasicAdapter = DS.Adapter.extend({ + find: function(store, type, id) { + var sync = type.sync; + + Ember.assert("You are trying to use the BasicAdapter to find id '" + id + "' of " + type + " but " + type + ".sync was not found", sync); + Ember.assert("The sync code on " + type + " does not implement find(), but you are trying to find id '" + id + "'.", sync.find); + + sync.find(id, processorFactory(store, type)); + }, + + findQuery: function(store, type, query, recordArray) { + var sync = type.sync; + + Ember.assert("You are trying to use the BasicAdapter to query " + type + " but " + type + ".sync was not found", sync); + Ember.assert("The sync code on " + type + " does not implement query(), but you are trying to query " + type + ".", sync.query); + + sync.query(query, arrayProcessorFactory(store, type, recordArray)); + } +}); + +DS.registerTransforms = function(kind, object) { + registeredTransforms[kind] = object; +}; + +DS.clearTransforms = function() { + registeredTransforms = {}; +}; + +DS.clearTransforms(); + +})(); + + + (function() { })(); diff --git a/architecture-examples/emberjs/js/models/store.js b/architecture-examples/emberjs/js/models/store.js index 58c42dbb6e..400a25cba5 100644 --- a/architecture-examples/emberjs/js/models/store.js +++ b/architecture-examples/emberjs/js/models/store.js @@ -2,7 +2,7 @@ 'use strict'; Todos.Store = DS.Store.extend({ - revision: 11, + revision: 12, adapter: 'Todos.LSAdapter' }); diff --git a/architecture-examples/emberjs/readme.md b/architecture-examples/emberjs/readme.md new file mode 100644 index 0000000000..621888ee0b --- /dev/null +++ b/architecture-examples/emberjs/readme.md @@ -0,0 +1,31 @@ +# Ember.js TodoMVC Example + +> A framework for creating ambitious web applications. + +> _[Ember.js - emberjs.com](http://emberjs.com)_ + + +## Learning Ember.js + +The [Ember.js website](http://emberjs.com) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Guides](http://emberjs.com/guides) +* [API Reference](http://emberjs.com/api) +* [Screencast - Building an App with Ember.js](https://www.youtube.com/watch?v=Ga99hMi7wfY) +* [Applications built with Ember.js](http://emberjs.com/ember-users) +* [Blog](http://emberjs.com/blog) + +Articles and guides from the community: + +* [Getting Into Ember.js](http://net.tutsplus.com/tutorials/javascript-ajax/getting-into-ember-js) +* [EmberWatch](http://emberwatch.com) + +Get help from other Ember.js users: + +* [Ember.js on StackOverflow](http://stackoverflow.com/questions/tagged/ember.js) +* [Ember.js on Twitter](http://twitter.com/emberjs) +* [Ember.js on Google +](https://plus.google.com/communities/106387049790387471205) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ diff --git a/architecture-examples/gwt/bower.json b/architecture-examples/gwt/bower.json new file mode 100644 index 0000000000..c0a637869f --- /dev/null +++ b/architecture-examples/gwt/bower.json @@ -0,0 +1,7 @@ +{ + "name": "gwt", + "version": "0.0.0", + "dependencies": { + "todomvc-common": "~0.1.6" + } +} \ No newline at end of file diff --git a/architecture-examples/dart/web/assets/base.css b/architecture-examples/gwt/bower_components/todomvc-common/base.css similarity index 76% rename from architecture-examples/dart/web/assets/base.css rename to architecture-examples/gwt/bower_components/todomvc-common/base.css index 672d939970..3e6bfaf38d 100644 --- a/architecture-examples/dart/web/assets/base.css +++ b/architecture-examples/gwt/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -155,22 +155,11 @@ label[for='toggle-all'] { #toggle-all { position: absolute; - top: -56px; - left: -15px; - width: 65px; - height: 41px; + top: -42px; + left: -4px; + width: 40px; text-align: center; border: none; /* Mobile Safari */ - -webkit-appearance: none; - /*-moz-appearance: none;*/ - -ms-appearance: none; - -o-appearance: none; - appearance: none; - -webkit-transform: rotate(90deg); - /*-moz-transform: rotate(90deg);*/ - -ms-transform: rotate(90deg); - /*-o-transform: rotate(90deg);*/ - transform: rotate(90deg); } #toggle-all:before { @@ -219,7 +208,8 @@ label[for='toggle-all'] { #todo-list li .toggle { text-align: center; width: 40px; - height: 40px; + /* auto, since non-WebKit browsers doesn't support input styling */ + height: auto; position: absolute; top: 0; bottom: 0; @@ -233,7 +223,6 @@ label[for='toggle-all'] { } #todo-list li .toggle:after { - font-size: 18px; content: '✔'; line-height: 43px; /* 40 + a couple of pixels visual adjustment */ font-size: 20px; @@ -403,8 +392,164 @@ label[for='toggle-all'] { #todo-list li .toggle { background: none; } + + #todo-list li .toggle { + height: 40px; + } + + #toggle-all { + top: -56px; + left: -15px; + width: 65px; + height: 41px; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + -webkit-appearance: none; + appearance: none; + } } .hidden{ display:none; -} \ No newline at end of file +} + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/architecture-examples/gwt/bower_components/todomvc-common/base.js b/architecture-examples/gwt/bower_components/todomvc-common/base.js new file mode 100644 index 0000000000..099da60dd1 --- /dev/null +++ b/architecture-examples/gwt/bower_components/todomvc-common/base.js @@ -0,0 +1,209 @@ +(function () { + 'use strict'; + + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + + if (location.hostname === 'todomvc.com') { + window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); + } + + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); + } + } + + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } + + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); + } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; + } + + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); + } + } + + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + + redirect(); + getFile('learn.json', Learn); +})(); diff --git a/labs/architecture-examples/meteor/client/images/bg.png b/architecture-examples/gwt/bower_components/todomvc-common/bg.png similarity index 100% rename from labs/architecture-examples/meteor/client/images/bg.png rename to architecture-examples/gwt/bower_components/todomvc-common/bg.png diff --git a/architecture-examples/gwt/css/app.css b/architecture-examples/gwt/css/app.css index dcc3949f86..39ce370449 100644 --- a/architecture-examples/gwt/css/app.css +++ b/architecture-examples/gwt/css/app.css @@ -1,13 +1,13 @@ /* The CSS that is common to all TodoMVC implementations, base.css, styles the selected routing filter using the following selector: - + #filters li a.selected - + In the GWT implementation, a Hyperlink widget is used for the routing filters. This widget allows you to specify a history - and will handle the clicks accordingly. The HTML for this widget is as follows: - +
      - + Where the 'div' element represents the hyperlink GWT widget. This results in the following GWT specific style. */ diff --git a/architecture-examples/gwt/index.html b/architecture-examples/gwt/index.html index 72aac46d5b..f2beb7031e 100644 --- a/architecture-examples/gwt/index.html +++ b/architecture-examples/gwt/index.html @@ -1,16 +1,14 @@ - - + + - - GWT • TodoMVC - + + Google Web Toolkit • TodoMVC + - + diff --git a/architecture-examples/gwt/readme.md b/architecture-examples/gwt/readme.md index 452eac1336..30c1291e75 100644 --- a/architecture-examples/gwt/readme.md +++ b/architecture-examples/gwt/readme.md @@ -1,20 +1,42 @@ -## TodoMVC - GWT Version +# Google Web Toolkit TodoMVC Example -This is a Google Web Toolkit (GWT) implementation of the TodoMVC application. The GWT version -is rather different to all the other TodoMVC versions (Backbone, Knockout etc ...) in that it is -written in Java which is compiled to JavaScript. The files within the `gwttodo` folder are the result -of running the GWT compilation process on the Java files found within the src folder. The UI -pattern used by this application is Model-View-Presenter. +> Google Web Toolkit (GWT) is a development toolkit for building and optimizing complex browser-based applications. GWT is used by many products at Google, including Google AdWords and Orkut. It's open source, completely free, and used by thousands of developers around the world. -Whilst this application is very different to the other TodoMVC implementations, it still makes for -an interesting comparison. Large-scale JavaScript applications are often written with GWT or Closure, -with the resulting JavaScript code delivered to the client being compiled. +> _[Google Web Toolkit - developers.google.com/web-toolkit](https://developers.google.com/web-toolkit)_ -You can read more about the implementation on my blog: -http://www.scottlogic.co.uk/blog/colin/2012/03/developing-a-gwt-todomvc-application/ +## Learning Google Web Toolkit -### Folder structure +The [Google Web Toolkit website](https://developers.google.com/web-toolkit/) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Documentation](https://developers.google.com/web-toolkit/doc/latest/DevGuide) +* [Getting Started with the GWT SDK](https://developers.google.com/web-toolkit/gettingstarted) +* [Articles](https://developers.google.com/web-toolkit/articles) +* [Case Studies](https://developers.google.com/web-toolkit/casestudies) +* [Blog](http://googlewebtoolkit.blogspot.com) +* [FAQ](https://developers.google.com/web-toolkit/doc/latest/FAQ) + +Get help from other Google Web Toolkit users: + +* [Google Web Toolkit on StackOverflow](http://stackoverflow.com/questions/tagged/gwt) +* [Mailing list on Google Groups](http://groups.google.com/group/Google-Web-Toolkit) +* [Google Web Toolkit on Twitter](http://twitter.com/googledevtools) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ + + +## Implementation + +This application is rather different than most of the other TodoMVC versions in that it is written in Java which is compiled to JavaScript. The files within the `gwttodo` folder are the result of running the GWT compilation process on the Java files found within the src folder. The UI pattern used by this application is Model-View-Presenter. + +Whilst this application is very different to the other implementations, it still makes for an interesting comparison. Large-scale JavaScript applications are often written with GWT or Closure, with the resulting JavaScript code delivered to the client being compiled. + +You can read more about the implementation on [my blog](http://www.scottlogic.co.uk/blog/colin/2012/03/developing-a-gwt-todomvc-application). + + +## Folder Structure - `css` - includes GWT specific `app.css`, most styling is taken from the base CSS file `../../assets/base.css` - `gwttodo` - the GWT compiled output, this includes various HTML files, which contain the JavaScript @@ -23,14 +45,8 @@ folder also includes some redundant files, see the issue 0) { - return location.pathname.replace(/todomvc\//, ''); + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); } - return location.pathname; } - function appendSourceLink() { - var sourceLink = document.createElement('a'); - var paragraph = document.createElement('p'); - var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } - if (footer) { - sourceLink.href = urlBase + getSourcePath(); - sourceLink.appendChild(document.createTextNode('Check out the source')); - paragraph.appendChild(sourceLink); - footer.appendChild(paragraph); + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; } - function redirect() { - if (location.hostname === 'addyosmani.github.io') { - location.href = location.href.replace('addyosmani.github.io/todomvc', 'todomvc.com'); + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); } } - appendSourceLink(); + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + redirect(); + getFile('learn.json', Learn); })(); diff --git a/architecture-examples/jquery/index.html b/architecture-examples/jquery/index.html index 86a49efed9..5d65d68fd0 100644 --- a/architecture-examples/jquery/index.html +++ b/architecture-examples/jquery/index.html @@ -1,8 +1,8 @@ - + - + jQuery • TodoMVC diff --git a/architecture-examples/jquery/js/app.js b/architecture-examples/jquery/js/app.js index fabd5a44c8..1bf77d569f 100644 --- a/architecture-examples/jquery/js/app.js +++ b/architecture-examples/jquery/js/app.js @@ -43,13 +43,14 @@ jQuery(function ($) { this.todoTemplate = Handlebars.compile($('#todo-template').html()); this.footerTemplate = Handlebars.compile($('#footer-template').html()); this.$todoApp = $('#todoapp'); - this.$newTodo = $('#new-todo'); - this.$toggleAll = $('#toggle-all'); - this.$main = $('#main'); - this.$todoList = $('#todo-list'); + this.$header = this.$todoApp.find('#header'); + this.$main = this.$todoApp.find('#main'); this.$footer = this.$todoApp.find('#footer'); - this.$count = $('#todo-count'); - this.$clearBtn = $('#clear-completed'); + this.$newTodo = this.$header.find('#new-todo'); + this.$toggleAll = this.$main.find('#toggle-all'); + this.$todoList = this.$main.find('#todo-list'); + this.$count = this.$footer.find('#todo-count'); + this.$clearBtn = this.$footer.find('#clear-completed'); }, bindEvents: function () { var list = this.$todoList; @@ -149,7 +150,10 @@ jQuery(function ($) { App.render(); }, edit: function () { - $(this).closest('li').addClass('editing').find('.edit').focus(); + var $input = $(this).closest('li').addClass('editing').find('.edit'); + var val = $input.val(); + + $input.val(val).focus(); }, blurOnEnter: function (e) { if (e.which === App.ENTER_KEY) { diff --git a/architecture-examples/jquery/readme.md b/architecture-examples/jquery/readme.md new file mode 100644 index 0000000000..6374690b23 --- /dev/null +++ b/architecture-examples/jquery/readme.md @@ -0,0 +1,33 @@ +# jQuery TodoMVC Example + +> jQuery is a fast, small, and feature-rich JavaScript library. It makes things like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler with an easy-to-use API that works across a multitude of browsers. With a combination of versatility and extensibility, jQuery has changed the way that millions of people write JavaScript. + +> _[jQuery - jquery.com](http://jquery.com)_ + + +## Learning jQuery + +The [jQuery website](http://jquery.com) is a great resource for getting started. + +Here are some links you may find helpful: + +* [How jQuery Works](http://learn.jquery.com/about-jquery/how-jquery-works) +* [API Reference](http://api.jquery.com) +* [Plugins](http://plugins.jquery.com) +* [Brower Support](http://jquery.com/browser-support) +* [Blog](http://blog.jquery.com) + +Articles and guides from the community: + +* [Try jQuery](http://try.jquery.com) +* [jQuery Annotated Source](http://github.com/robflaherty/jquery-annotated-source) +* [10 Things I Learned From the jQuery Source](http://paulirish.com/2010/10-things-i-learned-from-the-jquery-source) + +Get help from other jQuery users: + +* [jQuery on StackOverflow](http://stackoverflow.com/questions/tagged/jquery) +* [Forums](http://forum.jquery.com) +* [jQuery on Twitter](http://twitter.com/jquery) +* [jQuery on Google +](https://plus.google.com/102828491884671003608/posts) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ diff --git a/architecture-examples/knockback/bower.json b/architecture-examples/knockback/bower.json new file mode 100644 index 0000000000..947780ffb9 --- /dev/null +++ b/architecture-examples/knockback/bower.json @@ -0,0 +1,9 @@ +{ + "name": "todomvc-knockback", + "version": "0.0.0", + "dependencies": { + "jquery": "~2.0.0", + "todomvc-common": "~0.1.6", + "Backbone.localStorage": "~1.1.3" + } +} diff --git a/architecture-examples/knockback/bower_components/Backbone.localStorage/backbone.localStorage.js b/architecture-examples/knockback/bower_components/Backbone.localStorage/backbone.localStorage.js new file mode 100644 index 0000000000..792f51d6ce --- /dev/null +++ b/architecture-examples/knockback/bower_components/Backbone.localStorage/backbone.localStorage.js @@ -0,0 +1,217 @@ +/** + * Backbone localStorage Adapter + * Version 1.1.3 + * + * https://github.com/jeromegn/Backbone.localStorage + */ +(function (root, factory) { + if (typeof exports === 'object') { + module.exports = factory(require("underscore"), require("backbone")); + } else if (typeof define === "function" && define.amd) { + // AMD. Register as an anonymous module. + define(["underscore","backbone"], function(_, Backbone) { + // Use global variables if the locals are undefined. + return factory(_ || root._, Backbone || root.Backbone); + }); + } else { + // RequireJS isn't being used. Assume underscore and backbone are loaded in - - - + + + + + - - - - - - - - \ No newline at end of file + + + + + + + + diff --git a/architecture-examples/knockback/readme.md b/architecture-examples/knockback/readme.md index 53fcc1009b..24174635f5 100644 --- a/architecture-examples/knockback/readme.md +++ b/architecture-examples/knockback/readme.md @@ -1,14 +1,39 @@ -# Knockback.js • [TodoMVC](http://todomvc.com) +# Knockback.js TodoMVC Example -## Getting started +> Both Knockout.js and Backbone.js have their strengths and weaknesses, but together they are amazing! With Knockback.js, you can use the strong ORM provided by Backbone and create dynamic views using Knockout bindings. -You need [CoffeScript](http://coffeescript.org) to compile if you make changes to the files in the `src` folder. +> _[Knockback.js - kmalakoff.github.io/knockback](http://kmalakoff.github.io/knockback)_ -## Compile +## Learning Knockback.js -Open Terminal in this folder. +The [Knockback.js website](http://kmalakoff.github.io/knockback) is a great resource for getting started. -- `cake build` to compile once +Here are some links you may find helpful: -- `cake watch` to compile on save \ No newline at end of file +* [Getting Started with Knockback.js](http://kmalakoff.github.io/knockback/getting_started_introduction.html) +* [Tutorials](http://kmalakoff.github.io/knockback/tutorials_introduction.html) +* [API Reference](http://kmalakoff.github.io/knockback/doc/index.html) +* [Knockback.js Reference App](http://kmalakoff.github.io/knockback/app_knockback_reference.html) +* [Knockback.js on Twitter](http://twitter.com/knockbackjs) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ + + +## Running + +This app is written in [CoffeeScript](http://coffeescript.org/). If you wish to make changes, follow these steps to re-compile the code. + +To install CoffeeScript globally: + + npm install -g coffee-script + +To compile once: + + # from architecture-examples/knockback + cake build + +To compile on save + + # from architecture-examples/knockback + cake watch diff --git a/architecture-examples/knockoutjs/bower_components/todomvc-common/base.css b/architecture-examples/knockoutjs/bower_components/todomvc-common/base.css index 8d1db3a696..3e6bfaf38d 100644 --- a/architecture-examples/knockoutjs/bower_components/todomvc-common/base.css +++ b/architecture-examples/knockoutjs/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -412,3 +412,144 @@ label[for='toggle-all'] { .hidden{ display:none; } + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/architecture-examples/knockoutjs/bower_components/todomvc-common/base.js b/architecture-examples/knockoutjs/bower_components/todomvc-common/base.js index 3fd166d061..099da60dd1 100644 --- a/architecture-examples/knockoutjs/bower_components/todomvc-common/base.js +++ b/architecture-examples/knockoutjs/bower_components/todomvc-common/base.js @@ -1,38 +1,209 @@ (function () { 'use strict'; + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + if (location.hostname === 'todomvc.com') { window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); } - function getSourcePath() { - // If accessed via addyosmani.github.io/todomvc/, strip the project path. - if (location.hostname.indexOf('github.io') > 0) { - return location.pathname.replace(/todomvc\//, ''); + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); } - return location.pathname; } - function appendSourceLink() { - var sourceLink = document.createElement('a'); - var paragraph = document.createElement('p'); - var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } - if (footer) { - sourceLink.href = urlBase + getSourcePath(); - sourceLink.appendChild(document.createTextNode('Check out the source')); - paragraph.appendChild(sourceLink); - footer.appendChild(paragraph); + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; } - function redirect() { - if (location.hostname === 'addyosmani.github.io') { - location.href = location.href.replace('addyosmani.github.io/todomvc', 'todomvc.com'); + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); } } - appendSourceLink(); + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + redirect(); + getFile('learn.json', Learn); })(); diff --git a/architecture-examples/knockoutjs/index.html b/architecture-examples/knockoutjs/index.html index 6a8b22a71d..b90ecfe13a 100644 --- a/architecture-examples/knockoutjs/index.html +++ b/architecture-examples/knockoutjs/index.html @@ -1,5 +1,5 @@ - + diff --git a/architecture-examples/knockoutjs/readme.md b/architecture-examples/knockoutjs/readme.md index a4cccc9abc..1bf455a974 100644 --- a/architecture-examples/knockoutjs/readme.md +++ b/architecture-examples/knockoutjs/readme.md @@ -1,3 +1,36 @@ -# Knockout.js TodoMVC app +# Knockout.js TodoMVC Example -[ashish101](https://github.com/ashish01/knockoutjs-todos) wrote the original version of this application, which was then refactored by Addy Osmani and later rewritten by TodoMVC contributors. +> Knockout.js helps you simplify dynamic JavaScript UIs using the Model-View-ViewModel (MVVM) pattern. + +> _[Knockout.js - knockoutjs.com](http://knockoutjs.com)_ + + +## Learning Knockout.js + +The [Knockout.js website](http://knockoutjs.com) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Documentation](http://knockoutjs.com/documentation/introduction.html) +* [Tutorials](http://learn.knockoutjs.com) +* [Live examples](http://knockoutjs.com/examples) + +Articles and guides from the community: + +* [Getting Started with Knockout.js](http://www.adobe.com/devnet/html5/articles/getting-started-with-knockoutjs.html) +* [Into the Ring with Knockout.js](http://net.tutsplus.com/tutorials/javascript-ajax/into-the-ring-with-knockout-js) +* [Beginners Guide to Knockout.js](http://www.sitepoint.com/beginners-guide-to-knockoutjs-part-1) + +Get help from other Knockout.js users: + +* [Knockout.js on StackOverflow](http://stackoverflow.com/questions/tagged/knockout) +* [Mailing list on Google Groups](http://groups.google.com/group/knockoutjs) +* [Knockout.js on Twitter](http://twitter.com/knockoutjs) +* [Knockout.js on Google +](https://plus.google.com/communities/106789046312204355684/stream/c5bfcfdf-3690-44a6-b015-35aad4f4e42e) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ + + +## Credit + +This TodoMVC application was originally created by [ashish101](https://github.com/ashish01/knockoutjs-todos), then refactored by Addy Osmani and later rewritten by TodoMVC contributors. diff --git a/architecture-examples/maria/bower.json b/architecture-examples/maria/bower.json index e355cc9e49..2fcee3e366 100644 --- a/architecture-examples/maria/bower.json +++ b/architecture-examples/maria/bower.json @@ -3,6 +3,8 @@ "version": "0.0.0", "dependencies": { "todomvc-common": "~0.1.4", - "director": "~1.2.0" + "director": "~1.2.0", + "maria-bower": "~1.0.0", + "aristocrat-bower": "~1.0.1" } } diff --git a/architecture-examples/maria/lib/aristocrat/aristocrat.js b/architecture-examples/maria/bower_components/aristocrat-bower/aristocrat.js similarity index 98% rename from architecture-examples/maria/lib/aristocrat/aristocrat.js rename to architecture-examples/maria/bower_components/aristocrat-bower/aristocrat.js index 2095b86727..387d2320de 100644 --- a/architecture-examples/maria/lib/aristocrat/aristocrat.js +++ b/architecture-examples/maria/bower_components/aristocrat-bower/aristocrat.js @@ -1,5 +1,5 @@ /* -Aristocrat version 2 +Aristocrat version 1.0.1 Copyright (c) 2012, Peter Michaux All rights reserved. Licensed under the Simplified BSD License. @@ -78,7 +78,7 @@ aristocrat.removeClass(document.body, 'king'); var re = getRegExp(className); while (re.test(el.className)) { // in case multiple occurrences el.className = el.className.replace(re, ' '); - } + } }; /** diff --git a/architecture-examples/maria/lib/maria/maria.js b/architecture-examples/maria/bower_components/maria-bower/maria.js similarity index 94% rename from architecture-examples/maria/lib/maria/maria.js rename to architecture-examples/maria/bower_components/maria-bower/maria.js index 278f2841e3..2f747260c0 100644 --- a/architecture-examples/maria/lib/maria/maria.js +++ b/architecture-examples/maria/bower_components/maria-bower/maria.js @@ -1,6 +1,7 @@ +var maria = (function() { // IIFE /* -Evento version 0 - JavaScript libraries for working with the observer pattern -Copyright (c) 2012, Peter Michaux +Evento version 1 +Copyright (c) 2013, Peter Michaux All rights reserved. Licensed under the Simplified BSD License. https://github.com/petermichaux/evento/blob/master/LICENSE @@ -172,7 +173,7 @@ Call `evt.stopPropagation()` to stop bubbling to parents. */ evento.EventTarget.prototype.dispatchEvent = function(evt) { - // Want to ensure we don't alter the evt object passed in as it + // Want to ensure we don't alter the evt object passed in as it // may be a bubbling event. So clone it and then setting currentTarget // won't break some event that is already being dispatched. evt = create(evt); @@ -190,9 +191,9 @@ Call `evt.stopPropagation()` to stop bubbling to parents. // // Without making a copy, one listener removing // an already-called listener would result in skipping - // a not-yet-called listener. One listener removing + // a not-yet-called listener. One listener removing // a not-yet-called listener would result in skipping that - // not-yet-called listner. The worst case scenario + // not-yet-called listner. The worst case scenario // is a listener removing and adding itself again which would // create an infinite loop. // @@ -267,7 +268,7 @@ Example 2 (typeof pt[p] === 'function')) { obj[p] = pt[p]; } - } + } evento.EventTarget.call(obj); }; @@ -357,7 +358,7 @@ MVC application this can lead to "zombie views" if the model data cannot be garbage collected. Event listeners need to be removed from event targets in browsers with circular reference memory leak problems (i.e. old versions of Internet Explorer.) -The primary motivation for this `purge` function is to ease cleanup in MVC View destroy +The primary motivation for this `purge` function is to ease cleanup in MVC View destroy methods. For example, var APP_BoxView = function(model, controller) { @@ -456,13 +457,13 @@ methods. For example, if (indexOfBundle(listener._evento_bundles, bundle) >= 0) { // do not add the same listener twice return; - } + } } else { listener._evento_bundles = []; } if (typeof bundle.element.addEventListener === 'function') { - bundle.element.addEventListener(bundle.type, bundle.wrappedHandler, false); + bundle.element.addEventListener(bundle.type, bundle.wrappedHandler, false); } else if ((typeof bundle.element.attachEvent === 'object') && (bundle.element.attachEvent !== null)) { @@ -481,14 +482,14 @@ methods. For example, var bundle = listener._evento_bundles[i]; if (typeof bundle.element.removeEventListener === 'function') { bundle.element.removeEventListener(bundle.type, bundle.wrappedHandler, false); - } + } else if ((typeof bundle.element.detachEvent === 'object') && (bundle.element.detachEvent !== null)) { bundle.element.detachEvent('on'+bundle.type, bundle.wrappedHandler); - } + } else { throw new Error('evento.off: Supported EventTarget interface not found.'); - } + } listener._evento_bundles.splice(i, 1); } } @@ -511,7 +512,7 @@ methods. For example, }()); /* -Hijos version 3 +Hijos version 1.0.3 Copyright (c) 2013, Peter Michaux All rights reserved. Licensed under the Simplified BSD License. @@ -759,6 +760,11 @@ hijos.Node.prototype.insertBefore = function(newChild, oldChild) { } node = node.parentNode; } + // remove from previous composite + var parent = newChild.parentNode; + if (parent) { + parent.removeChild(newChild); + } // continue with insertion var children = this.childNodes; // find index for newChild @@ -778,11 +784,6 @@ hijos.Node.prototype.insertBefore = function(newChild, oldChild) { throw new Error('hijos.Node.prototype.insertBefore: Node was not found.'); } } - // remove from previous composite - var parent = newChild.parentNode; - if (parent) { - parent.removeChild(newChild); - } // add to this composite children.splice(indexForNewChild, 0, newChild); this.firstChild = children[0]; @@ -1018,7 +1019,7 @@ don't want to have a loop of thousands with calls to this function. // IE will trim when setting innerHTML so unify for all browsers html = trim(html); var parser = defaultParser; - var matches = html.match(tagRegExp); + var matches = html.match(tagRegExp); if (matches) { var name = matches[1].toLowerCase(); if (Object.prototype.hasOwnProperty.call(parsers, name)) { @@ -1219,8 +1220,8 @@ The rest of the details are the same as for grail.findAll. }()); /* -Hormigas version 4 -Copyright (c) 2012, Peter Michaux +Hormigas version 5 +Copyright (c) 2013, Peter Michaux All rights reserved. Licensed under the Simplified BSD License. https://github.com/petermichaux/hormigas/blob/master/LICENSE @@ -1243,7 +1244,7 @@ var hormigas = {}; function initSet(set) { set._hormigas_ObjectSet_elements = {}; - set.length = 0; + set.size = 0; } /** @@ -1259,17 +1260,17 @@ Do not attempt to add primitives or host objects in a `ObjectSet`. This is a compromise to make `ObjectSet` objects efficient for use in the model layer of your MVC-style application. -When using the set iterators (e.g. `forEach`, `map`) do not depend +When using the set iterators (e.g. `forEach`) do not depend on the order of iteration of the set's elements. `ObjectSet` objects are unordered. var set = new hormigas.ObjectSet(); // an empty set -`ObjectSet` objects have a `length` property that is the number of elements in the set. +`ObjectSet` objects have a `size` property that is the number of elements in the set. var alpha = {}; var beta = {}; var set = new hormigas.ObjectSet(alpha, beta, alpha); - set.length; // 2 + set.size; // 2 The methods of an `ObjectSet` object are inspired by the incomplete Harmony Set proposal and the `Array.prototype` iterators. @@ -1290,25 +1291,11 @@ Harmony Set proposal and the `Array.prototype` iterators. The number of elements in the set. -*/ -hormigas.ObjectSet.prototype.length = 0; - -/** - -Use to determine if the set has any elements or not. - - var alpha = {}; - var set = new hormigas.ObjectSet(alpha); - set.isEmpty(); // false - set['delete'](alpha); - set.isEmpty(); // true +@member hormigas.ObjectSet.prototype.size -@return {boolean} `true` if set is empty. Otherwise `false`. +@readonly */ - hormigas.ObjectSet.prototype.isEmpty = function() { - return this.length < 1; - }; /** @@ -1354,7 +1341,7 @@ If `element` is not already in the set then adds element to the set. element._hormigas_ObjectSet_id = getId(); } this._hormigas_ObjectSet_elements[element._hormigas_ObjectSet_id] = element; - this.length++; + this.size++; return true; } }; @@ -1380,7 +1367,7 @@ position so quote `delete`. hormigas.ObjectSet.prototype['delete'] = function(element) { if (this.has(element)) { delete this._hormigas_ObjectSet_elements[element._hormigas_ObjectSet_id]; - this.length--; + this.size--; return true; } else { @@ -1394,14 +1381,14 @@ If the set has elements then removes all the elements. var alpha = {}; var set = new hormigas.ObjectSet(alpha); - set.empty(); // true - set.empty(); // false + set.clear(); // true + set.clear(); // false @return {boolean} `true` if elements were deleted from the set as the result of this call. Otherwise `false` because no elements were in the set. */ - hormigas.ObjectSet.prototype.empty = function() { - if (this.length > 0) { + hormigas.ObjectSet.prototype.clear = function() { + if (this.size > 0) { initSet(this); return true; } @@ -1435,7 +1422,7 @@ Calls `callbackfn` for each element of the set. var beta = {value: 1}; var gamma = {value: 2}; var set = new hormigas.ObjectSet(alpha, beta, gamma); - set.forEach(function(element, set) { + set.forEach(function(element) { console.log(element.value); }); @@ -1448,7 +1435,7 @@ Calls `callbackfn` for each element of the set. var thisArg = arguments[1]; for (var p in this._hormigas_ObjectSet_elements) { if (Object.prototype.hasOwnProperty.call(this._hormigas_ObjectSet_elements, p)) { - callbackfn.call(thisArg, this._hormigas_ObjectSet_elements[p], this); + callbackfn.call(thisArg, this._hormigas_ObjectSet_elements[p]); } } }; @@ -1461,7 +1448,7 @@ Calls `callbackfn` for each element of the set. var two = {value: 2}; var three = {value: 3}; var set = new hormigas.ObjectSet(one, two, three); - set.every(function(element, set) { + set.every(function(element) { return element.value < 2; }); // false @@ -1476,7 +1463,7 @@ Calls `callbackfn` for each element of the set. var thisArg = arguments[1]; for (var p in this._hormigas_ObjectSet_elements) { if (Object.prototype.hasOwnProperty.call(this._hormigas_ObjectSet_elements, p) && - !callbackfn.call(thisArg, this._hormigas_ObjectSet_elements[p], this)) { + !callbackfn.call(thisArg, this._hormigas_ObjectSet_elements[p])) { return false; } } @@ -1491,7 +1478,7 @@ Calls `callbackfn` for each element of the set. var two = {value: 2}; var three = {value: 3}; var set = new hormigas.ObjectSet(one, two, three); - set.some(function(element, set) { + set.some(function(element) { return element.value < 2; }); // true @@ -1506,7 +1493,7 @@ Calls `callbackfn` for each element of the set. var thisArg = arguments[1]; for (var p in this._hormigas_ObjectSet_elements) { if (Object.prototype.hasOwnProperty.call(this._hormigas_ObjectSet_elements, p) && - callbackfn.call(thisArg, this._hormigas_ObjectSet_elements[p], this)) { + callbackfn.call(thisArg, this._hormigas_ObjectSet_elements[p])) { return true; } } @@ -1561,78 +1548,12 @@ iterated in the set. accumulator = elements[0]; } while (i < ilen) { - accumulator = callbackfn.call(undefined, accumulator, elements[i], this); + accumulator = callbackfn.call(undefined, accumulator, elements[i]); i++; } return accumulator; }; -/** - -Calls `callbackfn` for each element of the set. The values returned by `callbackfn` -are added to a new array. This new array is the value returned by map. - - var alpha = {length: 5}; - var beta = {length: 4}; - var gamma = {length: 5}; - var set = new hormigas.ObjectSet(alpha, beta, gamma); - set.map(function(element) { - return element.length; - }); // [5,5,4] or [5,4,5] or [4,5,5] - -@param {function} callbackfn The function to call for each element in the set. - -@param {Object} [thisArg] The object to use as the this object in calls to `callbackfn`. - -@return {Array} The mapped values. - -*/ - hormigas.ObjectSet.prototype.map = function(callbackfn /*, thisArg */) { - var thisArg = arguments[1]; - var result = []; - for (var p in this._hormigas_ObjectSet_elements) { - if (Object.prototype.hasOwnProperty.call(this._hormigas_ObjectSet_elements, p)) { - result.push(callbackfn.call(thisArg, this._hormigas_ObjectSet_elements[p], this)); - } - } - return result; - }; - -/** - -Calls callbackfn for each element of the set. If callbackfn returns true -for an element then that element is added to a new array. This new array -is the value returned by filter. - - var alpha = {length: 5}; - var beta = {length: 4}; - var gamma = {length: 5}; - var set = new hormigas.ObjectSet(alpha, beta, gamma); - set.filter(function(element) { - return element.length > 4; - }); // [alpha, gamma] or [gamma, alpha] - -@param {function} callbackfn The function to call for each element in the set. - -@param {object} [thisArg] The object to use as the this object in calls to `callbackfn`. - -@return {Array} The filtered values. - -*/ - hormigas.ObjectSet.prototype.filter = function(callbackfn /*, thisArg */) { - var thisArg = arguments[1]; - var result = []; - for (var p in this._hormigas_ObjectSet_elements) { - if (Object.prototype.hasOwnProperty.call(this._hormigas_ObjectSet_elements, p)) { - var element = this._hormigas_ObjectSet_elements[p]; - if (callbackfn.call(thisArg, element, this)) { - result.push(element); - } - } - } - return result; - }; - }()); // insure prototype object is initialized properly @@ -1668,12 +1589,11 @@ hormigas.ObjectSet.mixin = function(obj) { }; /** @license -Maria release candidate 6 - an MVC framework for JavaScript applications +Maria 1.0.0 Copyright (c) 2013, Peter Michaux All rights reserved. Licensed under the Simplified BSD License. -https://github.com/petermichaux/maria/blob/master/LICENSE - +http://peter.michaux.ca/downloads/maria/1.0.0/LICENSE */ /** @@ -1696,7 +1616,9 @@ maria.create = (function() { function F() {} return function(obj) { F.prototype = obj; - return new F(); + obj = new F(); + F.prototype = null; + return obj; }; }()); /** @@ -1754,9 +1676,7 @@ Add an event listener. See evento.on for description. */ -maria.on = function() { - evento.on.apply(this, arguments); -}; +maria.on = evento.on; /** @@ -1765,9 +1685,7 @@ Remove an event listener. See evento.off for description. */ -maria.off = function() { - evento.off.apply(this, arguments); -}; +maria.off = evento.off; /** @@ -1776,9 +1694,20 @@ Purge an event listener of all its subscriptions. See evento.purge for description. */ -maria.purge = function() { - evento.purge.apply(this, arguments); -}; +maria.purge = evento.purge; +/** + +See hijos.Leaf for description. + +*/ +maria.Leaf = hijos.Leaf; + +/** + +See hijos.Node for description. + +*/ +maria.Node = hijos.Node; /** A constructor function to create new model objects. @@ -1908,7 +1837,7 @@ with those elements. You can create an empty set model object. - var setModel = new maria.SetModel(); + var setModel = new maria.SetModel(); What makes a set model object interesting in comparison to a set is that a set model object is a model object that dispatches "change" @@ -1916,7 +1845,7 @@ events when elements are added or deleted from the the set. var view = { update: function(evt) { - alert(setModel.length + ' element(s) in the set.'); + alert(setModel.size + ' element(s) in the set.'); } }; maria.on(setModel, 'change', view, 'update'); @@ -1945,7 +1874,7 @@ You can check if an element is in the set. You can get the number of elements in the set. - setModel.length; // returns 2 + setModel.size; // returns 2 An element can be deleted from the set. Removing it multiple times has no effect. The delete method returns true if the element is @@ -1970,9 +1899,9 @@ setModel.delete if old browsers are not supported by your application. You can empty a set in one call. The method returns true if any elements are removed from the set model object. - setModel.empty(); // returns false, alpha and beta removed above. + setModel.clear(); // returns false, alpha and beta removed above. -If the call to empty does delete elements from the set, all "change" +If the call to `clear` does delete elements from the set, all "change" event listeners are passed an event object with deletedTargets just as for the delete method. @@ -2005,14 +1934,6 @@ A set model object has some other handy methods. return accumulator + element.name.length; }, 0); // returns 9 - setModel.map(function(element) { - return element.name.length; - }); // returns [4, 5] or [5, 4] - - setModel.filter(function(element) { - return element.name.length > 4; - }); // returns [alpha] - The order of the elements returned by toArray and the order of iteration of the other methods is undefined as a set is an unordered collection. Do not depend on any ordering that the current @@ -2029,19 +1950,16 @@ to accomplish the same. }; checkit.TodosModel.prototype = maria.create(maria.SetModel.prototype); checkit.TodosModel.prototype.constructor = checkit.TodosModel; - checkit.TodosModel.prototype.getDone = function() { - return this.filter(function(todo) { - return todo.isDone(); - }); - }; - checkit.TodosModel.prototype.getUndone = function() { - return this.filter(function(todo) { - return !todo.isDone(); - }); - }; checkit.TodosModel.prototype.isAllDone = function() { - return this.length > 0 && - (this.getDone().length === this.length); + return (this.size > 0) && + this.every(function(todo) { + return todo.isDone(); + }); + }; + checkit.TodosModel.prototype.isAllUndone = function() { + return this.every(function(todo) { + return !todo.isDone(); + }); }; checkit.TodosModel.prototype.markAllDone = function() { this.forEach(function(todo) { @@ -2054,7 +1972,13 @@ to accomplish the same. }); }; checkit.TodosModel.prototype.deleteDone = function() { - this['delete'].apply(this, this.getDone()); + var doneTodos = []; + this.forEach(function(todo) { + if (todo.isDone()) { + doneTodos.push(todo); + } + }); + this['delete'].apply(this, doneTodos); }; Another feature of set model objects is that events dispatched on @@ -2108,7 +2032,7 @@ maria.SetModel.prototype.add = function() { added.push(argument); if ((typeof argument.addEventListener === 'function') && (typeof argument.removeEventListener === 'function')) { - argument.addEventListener('destroy', this); + argument.addEventListener('destroy', this); } if ((typeof argument.addParentEventTarget === 'function') && // want to know can remove later @@ -2168,7 +2092,7 @@ maria.SetModel.prototype['delete'] = function() { Deletes all elements of the set. -If the set is modified as a result of this empty request then a `change` +If the set is modified as a result of this `clear` request then a `change` event is dispatched on the set model object. @override @@ -2176,9 +2100,9 @@ event is dispatched on the set model object. @return {boolean} True if the set was modified. Otherwise false. */ -maria.SetModel.prototype.empty = function() { +maria.SetModel.prototype.clear = function() { var deleted = this.toArray(); - var result = hormigas.ObjectSet.prototype.empty.call(this); + var result = hormigas.ObjectSet.prototype.clear.call(this); if (result) { for (var i = 0, ilen = deleted.length; i < ilen; i++) { var element = deleted[i]; @@ -2202,14 +2126,14 @@ must be deleted from this set. This handler will do the delete. @param {Object} event The event object. */ -maria.SetModel.prototype.handleEvent = function(ev) { +maria.SetModel.prototype.handleEvent = function(evt) { // If it is a destroy event being dispatched on the // destroyed element then we want to remove it from // this set. - if ((ev.type === 'destroy') && - (ev.currentTarget === ev.target)) { - this['delete'](ev.target); + if ((evt.type === 'destroy') && + (evt.currentTarget === evt.target)) { + this['delete'](evt.target); } }; @@ -2258,6 +2182,19 @@ getModelActions method. }; }; +By overriding the `getModelActions` method, the view will only observe +the model's `change` event if you explicitely list it which is not done +above. If you want to observe the `squashed`, `squished`, *and* `change` +events then you need to write the following. + + maria.View.prototype.getModelActions = function() { + return { + 'change' : 'update' , + 'squashed': 'onSquashed', + 'squished': 'onSquished' + }; + }; + When the model is set, if the view had a previous model then the view will unsubscribe from the events it subscribed to on the prevous model when the previous model was set. @@ -2267,7 +2204,7 @@ A view has a controller. You can get the current controller. view.getController(); The view's controller is created lazily the first time the -getController method is called. The view's +getController method is called. The view's getDefaultControllerConstructor method returns the constructor function to create the controller object and the getDefaultController actually calls that constructor. Your application may redefine or override @@ -2331,7 +2268,7 @@ accomplish the same. @constructor -@extends hijos.Node +@extends maria.Node @param {maria.Model} [model] @@ -2339,12 +2276,12 @@ accomplish the same. */ maria.View = function(model, controller) { - hijos.Node.call(this); + maria.Node.call(this); this.setModel(model); this.setController(controller); }; -maria.View.prototype = maria.create(hijos.Node.prototype); +maria.View.prototype = maria.create(maria.Node.prototype); maria.View.prototype.constructor = maria.View; /* @@ -2362,7 +2299,7 @@ maria.View.prototype.destroy = function() { this._controller.destroy(); this._controller = null; } - hijos.Node.prototype.destroy.call(this); + maria.Node.prototype.destroy.call(this); }; /** @@ -2408,7 +2345,7 @@ maria.View.prototype.setModel = function(model) { Returns a controller constructor function to be used to create a controller for this view. -@return {function} The controller constructor function. +@return {function} The controller constructor function. */ maria.View.prototype.getDefaultControllerConstructor = function() { @@ -2496,6 +2433,10 @@ maria.View.prototype._setModelAndController = function(model, controller) { } this._model = model; } + if ((this._controller !== controller) && this._controller) { + this._controller.setView(null); + this._controller.setModel(null); + } if (controller) { controller.setView(this); controller.setModel(model); @@ -2874,14 +2815,14 @@ By default Maria uses the Grail library as its DOM query engine. This is to support older browsers that do not have `querySelector`. The Grail engine only a limited set of simple selectors. - .class - tag - tag.class - #id + .class + tag + tag.class + #id -If your application only needs to work in newer browsers you can create -a Maria plugin to use `querySelector` but ensure the root element will -be returned if it matches `selector`. +If your application only needs to work in newer browsers then you can create +a Maria plugin to use `querySelector`. Consider if you want the root element +to be returned if it matches `selector`. If your application needs to work in older browsers but you need more complex CSS `selector` strings then you can create a Maria plugin @@ -3170,7 +3111,8 @@ maria.Controller.prototype.getModel = function() { /** -`setModel` is intended to be called **only** by +**Pretend you do not know that this method even exists.** +`setModel` is intended to be called **only** by the view `_setModelAndController` method. **Do otherwise at your own risk!** @@ -3194,7 +3136,8 @@ maria.Controller.prototype.getView = function() { /** -`setView` is intended to be called **only** by +**Pretend you do not know that this method even exists.** +`setView` is intended to be called **only** by the view `_setModelAndController` method. **Do otherwise at your own risk!** @@ -3256,19 +3199,16 @@ for maria.SetModel. maria.SetModel.subclass(checkit, 'TodosModel', { properties: { - getDone: function() { - return this.filter(function(todo) { - return todo.isDone(); - }); - }, - getUndone: function() { - return this.filter(function(todo) { - return !todo.isDone(); - }); - }, isAllDone: function() { - return this.length > 0 && - (this.getDone().length === this.length); + return (this.size > 0) && + this.every(function(todo) { + return todo.isDone(); + }); + }, + isAllUndone: function() { + return this.every(function(todo) { + return !todo.isDone(); + }); }, markAllDone: function() { this.forEach(function(todo) { @@ -3281,7 +3221,13 @@ for maria.SetModel. }); }, deleteDone: function() { - this['delete'].apply(this, this.getDone()); + var doneTodos = []; + this.forEach(function(todo) { + if (todo.isDone()) { + doneTodos.push(todo); + } + }); + this['delete'].apply(this, doneTodos); } } }); @@ -3526,3 +3472,5 @@ the documentation for maria.Controller. maria.Controller.subclass = function() { maria.subclass.apply(this, arguments); }; + +return maria;}()); // IIFE diff --git a/architecture-examples/maria/bower_components/todomvc-common/base.css b/architecture-examples/maria/bower_components/todomvc-common/base.css index 8d1db3a696..3e6bfaf38d 100644 --- a/architecture-examples/maria/bower_components/todomvc-common/base.css +++ b/architecture-examples/maria/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -412,3 +412,144 @@ label[for='toggle-all'] { .hidden{ display:none; } + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/architecture-examples/maria/bower_components/todomvc-common/base.js b/architecture-examples/maria/bower_components/todomvc-common/base.js index 3fd166d061..099da60dd1 100644 --- a/architecture-examples/maria/bower_components/todomvc-common/base.js +++ b/architecture-examples/maria/bower_components/todomvc-common/base.js @@ -1,38 +1,209 @@ (function () { 'use strict'; + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + if (location.hostname === 'todomvc.com') { window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); } - function getSourcePath() { - // If accessed via addyosmani.github.io/todomvc/, strip the project path. - if (location.hostname.indexOf('github.io') > 0) { - return location.pathname.replace(/todomvc\//, ''); + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); } - return location.pathname; } - function appendSourceLink() { - var sourceLink = document.createElement('a'); - var paragraph = document.createElement('p'); - var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } - if (footer) { - sourceLink.href = urlBase + getSourcePath(); - sourceLink.appendChild(document.createTextNode('Check out the source')); - paragraph.appendChild(sourceLink); - footer.appendChild(paragraph); + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; } - function redirect() { - if (location.hostname === 'addyosmani.github.io') { - location.href = location.href.replace('addyosmani.github.io/todomvc', 'todomvc.com'); + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); } } - appendSourceLink(); + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + redirect(); + getFile('learn.json', Learn); })(); diff --git a/architecture-examples/maria/index.html b/architecture-examples/maria/index.html index dbacde3ef0..26b394a3ce 100644 --- a/architecture-examples/maria/index.html +++ b/architecture-examples/maria/index.html @@ -1,33 +1,33 @@ - - - - - Maria • TodoMVC - - - - - + + + + + Maria • TodoMVC + + + + + - - - - + + + + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/architecture-examples/maria/js/models/TodosModel.js b/architecture-examples/maria/js/models/TodosModel.js index 24b4918e89..06cd63877a 100644 --- a/architecture-examples/maria/js/models/TodosModel.js +++ b/architecture-examples/maria/js/models/TodosModel.js @@ -30,19 +30,31 @@ maria.SetModel.subclass(checkit, 'TodosModel', { }, getCompleted: function () { - return this.filter(function (todo) { - return todo.isCompleted(); + var completeTodos = []; + this.forEach(function (todo) { + if (todo.isCompleted()) { + completeTodos.push(todo); + } }); + return completeTodos; }, getIncompleted: function () { - return this.filter(function (todo) { - return !todo.isCompleted(); + var incompleteTodos = []; + this.forEach(function (todo) { + if (!todo.isCompleted()) { + incompleteTodos.push(todo); + } }); + return incompleteTodos; }, isAllCompleted: function () { - return (this.length > 0) && (this.getCompleted().length === this.length); + return (this.size > 0) && (this.getCompleted().length === this.size); + }, + + isEmpty: function () { + return this.size === 0; }, markAllCompleted: function () { @@ -62,9 +74,11 @@ maria.SetModel.subclass(checkit, 'TodosModel', { }, toJSON: function () { - return this.map(function (todo) { - return todo.toJSON(); + var todoJSON = []; + this.forEach(function (todo) { + todoJSON.push(todo.toJSON()); }); + return todoJSON; } } }); diff --git a/architecture-examples/maria/js/views/TodosView.js b/architecture-examples/maria/js/views/TodosView.js index 325902edb4..d5c0a89cf5 100644 --- a/architecture-examples/maria/js/views/TodosView.js +++ b/architecture-examples/maria/js/views/TodosView.js @@ -12,7 +12,7 @@ maria.SetView.subclass(checkit, 'TodosAppView', { buildData: function () { var model = this.getModel(); - var length = model.length; + var length = model.size; this.find('#main').style.display = (length > 0) ? '' : 'none'; this.find('#footer').style.display = (length > 0) ? '' : 'none'; diff --git a/architecture-examples/maria/readme.md b/architecture-examples/maria/readme.md new file mode 100644 index 0000000000..1e8b58c55e --- /dev/null +++ b/architecture-examples/maria/readme.md @@ -0,0 +1,18 @@ +# Maria TodoMVC Example + +> The MVC framework for JavaScript applications. The real MVC. The Smalltalk MVC. The Gang of Four MVC. + +> _[Maria - peter.michaux.ca/maria](http://peter.michaux.ca/maria)_ + + +## Learning Maria + +The [Maria website](http://peter.michaux.ca/maria) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Quick Start Tutorial](http://peter.michaux.ca/maria/quick-start-tutorial-for-the-impatient.html) +* [API Reference](http://peter.michaux.ca/maria/api/maria.html) +* [GitHub](https://github.com/petermichaux/maria) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ diff --git a/architecture-examples/polymer/AUTHORS b/architecture-examples/polymer/AUTHORS new file mode 100644 index 0000000000..0617765756 --- /dev/null +++ b/architecture-examples/polymer/AUTHORS @@ -0,0 +1,9 @@ +# Names should be added to this file with this pattern: +# +# For individuals: +# Name +# +# For organizations: +# Organization +# +Google Inc. <*@google.com> diff --git a/architecture-examples/polymer/CONTRIBUTING.md b/architecture-examples/polymer/CONTRIBUTING.md new file mode 100644 index 0000000000..9a37da351a --- /dev/null +++ b/architecture-examples/polymer/CONTRIBUTING.md @@ -0,0 +1,63 @@ +# Contributing + +Want to contribute to Polymer? Great! + +We are more than happy to accept external contributions to the project in the form of [feedback](https://groups.google.com/forum/?fromgroups=#!forum/polymer-dev), [bug reports](../../issues), and pull requests. + +## Contributor License Agreement + +Before we can accept patches, there's a quick web form you need to fill out. + +- If you're contributing as and individual (e.g. you own the intellectual property), fill out [this form](http://code.google.com/legal/individual-cla-v1.0.html). +- If you're contributing under a company, fill out [this form](http://code.google.com/legal/corporate-cla-v1.0.html) instead. + +This CLA asserts that contributions are owned by you and that we can license all work under our [license](LICENSE). + +Other projects require a similar agreement: jQuery, Firefox, Apache, Node, and many more. + +[More about CLAs](https://www.google.com/search?q=Contributor%20License%20Agreement) + +## Initial setup + +Here's an easy guide that should get you up and running: + +1. Fork the project on github and pull down your copy. + > replace the {{ username }} with your username and {{ repository }} with the repository name + + git clone git@github.com:{{ username }}/{{ repository }}.git --recursive + + Note the `--recursive`. This is necessary for submodules to initialize properly. If you don't do a recursive clone, you'll have to init them manually: + + git submodule init + git submodule update + +2. Development happens on the `master` branch. Get yourself on it! + + git checkout master + +That's it for the one time setup. Now you're ready to make a change. + +## Submitting a pull request + +We iterate fast! To avoid potential merge conflicts, it's a good idea to pull from the main project before making a change and submitting a pull request. The easiest way to do this is setup a remote called `upstream` and do a pull before working on a change: + + git remote add upstream git://github.com/Polymer/{{ repository }}.git + +Then before making a change, do a pull from the upstream `master` branch: + + git pull upstream master + +To make life easier, add a "pull upstream" alias in your `.gitconfig`: + + [alias] + pu = !"git fetch origin -v; git fetch upstream -v; git merge upstream/master" + +That will pull in changes from your forked repo, the main (upstream) repo, and merge the two. Then it's just a matter of running `git pu` before a change and pushing to your repo: + + git checkout master + git pu + # make change + git commit -a -m 'Awesome things.' + git push + +Lastly, don't forget to submit the pull request. diff --git a/architecture-examples/polymer/LICENSE b/architecture-examples/polymer/LICENSE new file mode 100644 index 0000000000..92d60b019f --- /dev/null +++ b/architecture-examples/polymer/LICENSE @@ -0,0 +1,27 @@ +// Copyright (c) 2012 The Polymer Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/architecture-examples/polymer/PATENTS b/architecture-examples/polymer/PATENTS new file mode 100644 index 0000000000..e120963325 --- /dev/null +++ b/architecture-examples/polymer/PATENTS @@ -0,0 +1,23 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Polymer project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Polymer, where such license applies only to those +patent claims, both currently owned or controlled by Google and acquired +in the future, licensable by Google that are necessarily infringed by +this implementation of Polymer. This grant does not include claims +that would be infringed only as a consequence of further modification of +this implementation. If you or your agent or exclusive licensee +institute or order or agree to the institution of patent litigation +against any entity (including a cross-claim or counterclaim in a +lawsuit) alleging that this implementation of Polymer or any code +incorporated within this implementation of Polymer constitutes +direct or contributory patent infringement, or inducement of patent +infringement, then any patent rights granted to you under this License +for this implementation of Polymer shall terminate as of the date +such litigation is filed. diff --git a/architecture-examples/polymer/README.md b/architecture-examples/polymer/README.md new file mode 100644 index 0000000000..25449a118b --- /dev/null +++ b/architecture-examples/polymer/README.md @@ -0,0 +1,44 @@ +# Polymer TodoMVC Example + +> Polymer is a new type of library for the web, built on top of Web Components, and designed to leverage the evolving web platform on modern browsers. + +> _[Polymer - www.polymer-project.org](http://www.polymer-project.org/)_ + +## Learning Polymer + +The [Polymer website](http://www.polymer-project.org) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Getting Started](http://www.polymer-project.org/getting-started.html) +* [FAQ](http://www.polymer-project.org/faq.html) +* [Browser Compatibility](http://www.polymer-project.org/compatibility.html) + +Get help from Polymer devs and users: + +* Find us on IRC on __#polymer__ at freenode. +* Join the high-traffic [polymer-dev](https://groups.google.com/forum/?fromgroups=#!forum/polymer-dev) Google group or the announcement-only [polymer-announce](https://groups.google.com/forum/?fromgroups=#!forum/polymer-announce) Google group. + +## Implementation + +The Polymer implementation of TodoMVC has a few key differences with other implementations: + +* Since [Web Components](https://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html) allow you to create new types of DOM elements, the DOM tree is very different from other implementations. +* The template, styling, and behavior are fully encapsulated in each custom element. Instead of having an overall stylesheet (`base.css` or `app.css`), each element that needs styling has its own stylesheet. +* Non-visual elements such as the router and the model are also implemented as custom elements and appear in the DOM. Implementing them as custom elements instead of plain objects allows you to take advantage of Polymer data binding and event handling throughout the app. + +## Compatibility + +Polymer and its polyfills are intended to work in the latest version of [evergreen browsers](http://tomdale.net/2013/05/evergreen-browsers/). IE9 is not supported. Please refer to [Browser Compatibility](http://www.polymer-project.org/compatibility.html) for more details. + +## Running this sample + +1. Install [node.js](nodejs.org) (required for `bower` client-side package management) +1. Install bower: `npm install -g bower` + +1. From the `todomvc\` folder, run `bower update` +1. Start a web server in the `todomvc\` folder. Hint: if you have python installed, you can just run: + + `python -m SimpleHTTPServer` + +1. Browse to the server root diff --git a/architecture-examples/polymer/app/app.css b/architecture-examples/polymer/app/app.css new file mode 100644 index 0000000000..1442dbb03c --- /dev/null +++ b/architecture-examples/polymer/app/app.css @@ -0,0 +1,206 @@ +/* base.css overrides */ + +html, +body { + margin: 0; + padding: 0; +} + +body { + font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; + line-height: 1.4em; + background: #eaeaea url('../bower_components/todomvc-common/bg.png'); + color: #4d4d4d; + width: 550px; + margin: 0 auto; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + -ms-font-smoothing: antialiased; + -o-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +body > header { + padding-top: 22px; + margin-bottom: -5px; +} + +h1 { + /* position: absolute; + top: -120px;*/ + width: 100%; + font-size: 70px; + font-weight: bold; + text-align: center; + color: #b3b3b3; + color: rgba(255, 255, 255, 0.3); + text-shadow: -1px -1px rgba(0, 0, 0, 0.2); + -webkit-text-rendering: optimizeLegibility; + -moz-text-rendering: optimizeLegibility; + -ms-text-rendering: optimizeLegibility; + -o-text-rendering: optimizeLegibility; + text-rendering: optimizeLegibility; +} + +#info { + margin: 65px auto 0; + color: #a6a6a6; + font-size: 12px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7); + text-align: center; +} + +#info a { + color: inherit; +} + +.hidden{ + display:none; +} + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + + +/* IE doesn't support the hidden attribute */ +[hidden] { + display: none; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/labs/dependency-examples/troopjs/bower.json b/architecture-examples/polymer/bower.json similarity index 50% rename from labs/dependency-examples/troopjs/bower.json rename to architecture-examples/polymer/bower.json index 99b9459954..e112862b22 100644 --- a/labs/dependency-examples/troopjs/bower.json +++ b/architecture-examples/polymer/bower.json @@ -1,9 +1,9 @@ { - "name": "todomvc-troopjs", + "name": "todomvc-polymer", "version": "0.0.0", "dependencies": { "todomvc-common": "~0.1.4", - "requirejs": "~2.1.5", - "jquery": "<=1.8.2" + "director": "*", + "polymer": "*" } } diff --git a/architecture-examples/polymer/bower_components/director/build/director.js b/architecture-examples/polymer/bower_components/director/build/director.js new file mode 100644 index 0000000000..0befbe0751 --- /dev/null +++ b/architecture-examples/polymer/bower_components/director/build/director.js @@ -0,0 +1,712 @@ + + +// +// Generated on Sun Dec 16 2012 22:47:05 GMT-0500 (EST) by Nodejitsu, Inc (Using Codesurgeon). +// Version 1.1.9 +// + +(function (exports) { + + +/* + * browser.js: Browser specific functionality for director. + * + * (C) 2011, Nodejitsu Inc. + * MIT LICENSE + * + */ + +if (!Array.prototype.filter) { + Array.prototype.filter = function(filter, that) { + var other = [], v; + for (var i = 0, n = this.length; i < n; i++) { + if (i in this && filter.call(that, v = this[i], i, this)) { + other.push(v); + } + } + return other; + }; +} + +if (!Array.isArray){ + Array.isArray = function(obj) { + return Object.prototype.toString.call(obj) === '[object Array]'; + }; +} + +var dloc = document.location; + +function dlocHashEmpty() { + // Non-IE browsers return '' when the address bar shows '#'; Director's logic + // assumes both mean empty. + return dloc.hash === '' || dloc.hash === '#'; +} + +var listener = { + mode: 'modern', + hash: dloc.hash, + history: false, + + check: function () { + var h = dloc.hash; + if (h != this.hash) { + this.hash = h; + this.onHashChanged(); + } + }, + + fire: function () { + if (this.mode === 'modern') { + this.history === true ? window.onpopstate() : window.onhashchange(); + } + else { + this.onHashChanged(); + } + }, + + init: function (fn, history) { + var self = this; + this.history = history; + + if (!Router.listeners) { + Router.listeners = []; + } + + function onchange(onChangeEvent) { + for (var i = 0, l = Router.listeners.length; i < l; i++) { + Router.listeners[i](onChangeEvent); + } + } + + //note IE8 is being counted as 'modern' because it has the hashchange event + if ('onhashchange' in window && (document.documentMode === undefined + || document.documentMode > 7)) { + // At least for now HTML5 history is available for 'modern' browsers only + if (this.history === true) { + // There is an old bug in Chrome that causes onpopstate to fire even + // upon initial page load. Since the handler is run manually in init(), + // this would cause Chrome to run it twise. Currently the only + // workaround seems to be to set the handler after the initial page load + // http://code.google.com/p/chromium/issues/detail?id=63040 + setTimeout(function() { + window.onpopstate = onchange; + }, 500); + } + else { + window.onhashchange = onchange; + } + this.mode = 'modern'; + } + else { + // + // IE support, based on a concept by Erik Arvidson ... + // + var frame = document.createElement('iframe'); + frame.id = 'state-frame'; + frame.style.display = 'none'; + document.body.appendChild(frame); + this.writeFrame(''); + + if ('onpropertychange' in document && 'attachEvent' in document) { + document.attachEvent('onpropertychange', function () { + if (event.propertyName === 'location') { + self.check(); + } + }); + } + + window.setInterval(function () { self.check(); }, 50); + + this.onHashChanged = onchange; + this.mode = 'legacy'; + } + + Router.listeners.push(fn); + + return this.mode; + }, + + destroy: function (fn) { + if (!Router || !Router.listeners) { + return; + } + + var listeners = Router.listeners; + + for (var i = listeners.length - 1; i >= 0; i--) { + if (listeners[i] === fn) { + listeners.splice(i, 1); + } + } + }, + + setHash: function (s) { + // Mozilla always adds an entry to the history + if (this.mode === 'legacy') { + this.writeFrame(s); + } + + if (this.history === true) { + window.history.pushState({}, document.title, s); + // Fire an onpopstate event manually since pushing does not obviously + // trigger the pop event. + this.fire(); + } else { + dloc.hash = (s[0] === '/') ? s : '/' + s; + } + return this; + }, + + writeFrame: function (s) { + // IE support... + var f = document.getElementById('state-frame'); + var d = f.contentDocument || f.contentWindow.document; + d.open(); + d.write(" + diff --git a/architecture-examples/polymer/elements/td-item.css b/architecture-examples/polymer/elements/td-item.css new file mode 100644 index 0000000000..c29937b48d --- /dev/null +++ b/architecture-examples/polymer/elements/td-item.css @@ -0,0 +1,160 @@ +/* base.css overrides */ +@host { + .editing { + border-bottom: none; + padding: 0; + } +} + +button { + margin: 0; + padding: 0; + border: 0; + background-color: transparent; + background-image: none; + font-size: 100%; + vertical-align: baseline; + font-family: inherit; + color: inherit; + -webkit-appearance: none; + /*-moz-appearance: none;*/ + -ms-appearance: none; + -o-appearance: none; + appearance: none; +} + + +.edit { + position: relative; + margin: 0; + width: 100%; + font-size: 24px; + font-family: inherit; + line-height: 1.4em; + border: 0; + outline: none; + color: inherit; + padding: 6px; + border: 1px solid #999; + box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + -o-box-sizing: border-box; + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + -ms-font-smoothing: antialiased; + -o-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +.edit { + width: 506px; + padding: 13px 17px 12px 17px; + margin: 0 0 0 43px; +} + +.toggle { + text-align: center; + width: 40px; + /* auto, since non-WebKit browsers doesn't support input styling */ + height: auto; + position: absolute; + top: 0; + bottom: 0; + margin: auto 0; + border: none; /* Mobile Safari */ + -webkit-appearance: none; + /*-moz-appearance: none;*/ + -ms-appearance: none; + -o-appearance: none; + appearance: none; +} + +.toggle:after { + content: '✔'; + line-height: 43px; /* 40 + a couple of pixels visual adjustment */ + font-size: 20px; + color: #d9d9d9; + text-shadow: 0 -1px 0 #bfbfbf; +} + +.toggle:checked:after { + color: #85ada7; + text-shadow: 0 1px 0 #669991; + bottom: 1px; + position: relative; +} + +label { + word-break: break-word; + padding: 15px; + margin-left: 45px; + display: block; + line-height: 1.2; + -webkit-transition: color 0.4s; + -moz-transition: color 0.4s; + -ms-transition: color 0.4s; + -o-transition: color 0.4s; + transition: color 0.4s; +} + +.completed label { + color: #a9a9a9; + text-decoration: line-through; +} + +.destroy { + display: none; + position: absolute; + top: 0; + right: 10px; + bottom: 0; + width: 40px; + height: 40px; + margin: auto 0; + font-size: 22px; + color: #a88a8a; + -webkit-transition: all 0.2s; + -moz-transition: all 0.2s; + -ms-transition: all 0.2s; + -o-transition: all 0.2s; + transition: all 0.2s; +} + +.destroy:hover { + text-shadow: 0 0 1px #000, 0 0 10px rgba(199, 107, 107, 0.8); + -webkit-transform: scale(1.3); + -moz-transform: scale(1.3); + -ms-transform: scale(1.3); + -o-transform: scale(1.3); + transform: scale(1.3); +} + +.destroy:after { + content: '✖'; +} + +.view:hover .destroy { + display: block; +} + +/* + Hack to remove background from Mobile Safari. + Can't use it globally since it destroys checkboxes in Firefox and Opera +*/ +@media screen and (-webkit-min-device-pixel-ratio:0) { + .toggle { + background: none; + /* + ShadowDOM Polyfill work around for webkit/blink bug + https://code.google.com/p/chromium/issues/detail?id=251510 + */ + background-color: transparent; + } + + .toggle { + height: 40px; + } +} diff --git a/architecture-examples/polymer/elements/td-item.html b/architecture-examples/polymer/elements/td-item.html new file mode 100644 index 0000000000..f17ba48f12 --- /dev/null +++ b/architecture-examples/polymer/elements/td-item.html @@ -0,0 +1,56 @@ + + + + + diff --git a/architecture-examples/polymer/elements/td-model.html b/architecture-examples/polymer/elements/td-model.html new file mode 100644 index 0000000000..ebeeb517b8 --- /dev/null +++ b/architecture-examples/polymer/elements/td-model.html @@ -0,0 +1,74 @@ + + + diff --git a/labs/architecture-examples/ariatemplates/css/app.css b/architecture-examples/polymer/elements/td-todos.css similarity index 70% rename from labs/architecture-examples/ariatemplates/css/app.css rename to architecture-examples/polymer/elements/td-todos.css index 532c9b83c7..781a2f06bb 100644 --- a/labs/architecture-examples/ariatemplates/css/app.css +++ b/architecture-examples/polymer/elements/td-todos.css @@ -1,7 +1,10 @@ -html, -body { - margin: 0; - padding: 0; +/* base.css overrides */ + +@host { + * { + display: block; + position: relative; + } } button { @@ -14,30 +17,29 @@ button { font-family: inherit; color: inherit; -webkit-appearance: none; - /*-moz-appearance: none;*/ -ms-appearance: none; -o-appearance: none; appearance: none; } -body { - font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; - line-height: 1.4em; - background: #eaeaea url('../../../../assets/bg.png'); - color: #4d4d4d; - width: 550px; - margin: 0 auto; - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: antialiased; - -ms-font-smoothing: antialiased; - -o-font-smoothing: antialiased; - font-smoothing: antialiased; +input::-webkit-input-placeholder { + font-style: italic; +} + +input::-moz-placeholder { + font-style: italic; + color: #a9a9a9; +} + +input:-ms-input-placeholder, #new-todo:-ms-input-placeholder { + font-style: italic; + color: #a9a9a9; } #todoapp { background: #fff; background: rgba(255, 255, 255, 0.9); - margin: 130px 0 40px 0; + margin: 0 0 40px 0; border: 1px solid #ccc; position: relative; border-top-left-radius: 2px; @@ -57,32 +59,6 @@ body { height: 100%; } -#todoapp input::-webkit-input-placeholder { - font-style: italic; -} - -#todoapp input:-moz-placeholder { - font-style: italic; - color: #a9a9a9; -} - -#todoapp h1 { - position: absolute; - top: -120px; - width: 100%; - font-size: 70px; - font-weight: bold; - text-align: center; - color: #b3b3b3; - color: rgba(255, 255, 255, 0.3); - text-shadow: -1px -1px rgba(0, 0, 0, 0.2); - -webkit-text-rendering: optimizeLegibility; - -moz-text-rendering: optimizeLegibility; - -ms-text-rendering: optimizeLegibility; - -o-text-rendering: optimizeLegibility; - text-rendering: optimizeLegibility; -} - #header { padding-top: 15px; border-radius: inherit; @@ -149,6 +125,51 @@ body { border-top: 1px dotted #adadad; } +label[for='toggle-all'] { + display: none; +} + +#toggle-all { + position: absolute; + top: -42px; + left: -4px; + width: 40px; + text-align: center; + border: none; /* Mobile Safari */ +} + +#toggle-all:before { + content: '»'; + font-size: 28px; + color: #d9d9d9; + padding: 0 25px 7px; +} + +#toggle-all:checked:before { + color: #737373; +} + +#todo-list { + margin: 0; + padding: 0; + list-style: none; +} + +#todo-list li { + position: relative; + font-size: 24px; + border-bottom: 1px dotted #ccc; +} + +#todo-list li:last-child { + border-bottom: none; +} + +#todo-list li.editing { + border-bottom: none; + padding: 0; +} + #footer { color: #777; padding: 0 15px; @@ -181,6 +202,29 @@ body { text-align: left; } +#filters { + margin: 0; + padding: 0; + list-style: none; + position: absolute; + right: 0; + left: 0; +} + +#filters li { + display: inline; +} + +#filters li a { + color: #83756f; + margin: 2px; + text-decoration: none; +} + +#filters li.polymer-selected a { + font-weight: bold; +} + #clear-completed { float: right; position: relative; @@ -198,18 +242,24 @@ body { box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.3); } -#info { - margin: 65px auto 0; - color: #a6a6a6; - font-size: 12px; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7); - text-align: center; -} - -#info a { - color: inherit; -} +@media screen and (-webkit-min-device-pixel-ratio:0) { + #toggle-all { + background: none; + /* + ShadowDOM Polyfill work around for webkit/blink bug + https://code.google.com/p/chromium/issues/detail?id=251510 + */ + background-color: transparent; + } -.hidden{ - display:none; + #toggle-all { + top: -56px; + left: -15px; + width: 65px; + height: 41px; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + -webkit-appearance: none; + appearance: none; + } } diff --git a/architecture-examples/polymer/elements/td-todos.html b/architecture-examples/polymer/elements/td-todos.html new file mode 100644 index 0000000000..9459f6cc5a --- /dev/null +++ b/architecture-examples/polymer/elements/td-todos.html @@ -0,0 +1,81 @@ + + + + + + + + + + + diff --git a/architecture-examples/polymer/index.html b/architecture-examples/polymer/index.html new file mode 100644 index 0000000000..9e25f2c730 --- /dev/null +++ b/architecture-examples/polymer/index.html @@ -0,0 +1,29 @@ + + + + + + Polymer • TodoMVC + + + + + + +
      + + + + +
      + + + + + diff --git a/architecture-examples/polymer/lib-elements/flatiron-director.html b/architecture-examples/polymer/lib-elements/flatiron-director.html new file mode 100644 index 0000000000..19b94b3d87 --- /dev/null +++ b/architecture-examples/polymer/lib-elements/flatiron-director.html @@ -0,0 +1,31 @@ + + + + diff --git a/architecture-examples/polymer/lib-elements/polymer-localstorage.html b/architecture-examples/polymer/lib-elements/polymer-localstorage.html new file mode 100644 index 0000000000..b8abba18fa --- /dev/null +++ b/architecture-examples/polymer/lib-elements/polymer-localstorage.html @@ -0,0 +1,53 @@ + + + + + + diff --git a/architecture-examples/polymer/lib-elements/polymer-selection.html b/architecture-examples/polymer/lib-elements/polymer-selection.html new file mode 100644 index 0000000000..e2992dd72c --- /dev/null +++ b/architecture-examples/polymer/lib-elements/polymer-selection.html @@ -0,0 +1,64 @@ + + + + + + diff --git a/architecture-examples/polymer/lib-elements/polymer-selector.html b/architecture-examples/polymer/lib-elements/polymer-selector.html new file mode 100644 index 0000000000..bef3ab5ee5 --- /dev/null +++ b/architecture-examples/polymer/lib-elements/polymer-selector.html @@ -0,0 +1,198 @@ + + + + + + + + diff --git a/architecture-examples/spine/bower_components/todomvc-common/base.css b/architecture-examples/spine/bower_components/todomvc-common/base.css index 8d1db3a696..3e6bfaf38d 100644 --- a/architecture-examples/spine/bower_components/todomvc-common/base.css +++ b/architecture-examples/spine/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -412,3 +412,144 @@ label[for='toggle-all'] { .hidden{ display:none; } + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/architecture-examples/spine/bower_components/todomvc-common/base.js b/architecture-examples/spine/bower_components/todomvc-common/base.js index 3fd166d061..099da60dd1 100644 --- a/architecture-examples/spine/bower_components/todomvc-common/base.js +++ b/architecture-examples/spine/bower_components/todomvc-common/base.js @@ -1,38 +1,209 @@ (function () { 'use strict'; + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + if (location.hostname === 'todomvc.com') { window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); } - function getSourcePath() { - // If accessed via addyosmani.github.io/todomvc/, strip the project path. - if (location.hostname.indexOf('github.io') > 0) { - return location.pathname.replace(/todomvc\//, ''); + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); } - return location.pathname; } - function appendSourceLink() { - var sourceLink = document.createElement('a'); - var paragraph = document.createElement('p'); - var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } - if (footer) { - sourceLink.href = urlBase + getSourcePath(); - sourceLink.appendChild(document.createTextNode('Check out the source')); - paragraph.appendChild(sourceLink); - footer.appendChild(paragraph); + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; } - function redirect() { - if (location.hostname === 'addyosmani.github.io') { - location.href = location.href.replace('addyosmani.github.io/todomvc', 'todomvc.com'); + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); } } - appendSourceLink(); + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + redirect(); + getFile('learn.json', Learn); })(); diff --git a/architecture-examples/spine/index.html b/architecture-examples/spine/index.html index e11f9697a9..66e1bfa445 100644 --- a/architecture-examples/spine/index.html +++ b/architecture-examples/spine/index.html @@ -1,65 +1,65 @@ - - - - - Spine.js • TodoMVC - - - -
      - -
      - - -
        + + + + + Spine.js • TodoMVC + + + +
        + +
        + + +
          +
          +
          -
          - - - - - - - - + + + + + + + - - - - + + + + diff --git a/architecture-examples/spine/js/app.js b/architecture-examples/spine/js/app.js index b892274107..26c5a61141 100644 --- a/architecture-examples/spine/js/app.js +++ b/architecture-examples/spine/js/app.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.6.2 +// Generated by CoffeeScript 1.6.3 (function() { var TodoApp, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, @@ -33,7 +33,8 @@ this.renderFooter = __bind(this.renderFooter, this); this.toggleElems = __bind(this.toggleElems, this); this.addAll = __bind(this.addAll, this); - this.addNew = __bind(this.addNew, this); TodoApp.__super__.constructor.apply(this, arguments); + this.addNew = __bind(this.addNew, this); + TodoApp.__super__.constructor.apply(this, arguments); Todo.bind('create', this.addNew); Todo.bind('refresh change', this.addAll); Todo.bind('refresh change', this.toggleElems); @@ -54,7 +55,6 @@ TodoApp.prototype["new"] = function(e) { var val; - val = $.trim(this.newTodoInput.val()); if (e.which === ENTER_KEY && val) { Todo.create({ @@ -77,7 +77,6 @@ TodoApp.prototype.addNew = function(todo) { var view; - view = new Todos({ todo: todo }); @@ -86,7 +85,6 @@ TodoApp.prototype.addAll = function() { var todo, _i, _len, _ref, _results; - this.todos.empty(); _ref = this.getByFilter(); _results = []; @@ -103,6 +101,7 @@ TODO: Model updateAttribute sometimes won't stick: https://github.com/maccman/spine/issues/219 */ + todo.updateAttribute('completed', e.target.checked); return todo.trigger('update', todo); }); @@ -114,7 +113,6 @@ TodoApp.prototype.toggleElems = function() { var isTodos; - isTodos = !!Todo.count(); this.main.toggle(isTodos); this.footer.toggle(isTodos); @@ -126,7 +124,6 @@ TodoApp.prototype.renderFooter = function() { var active, completed, text; - text = function(count) { if (count === 1) { return 'item'; diff --git a/architecture-examples/spine/js/controllers/todos.js b/architecture-examples/spine/js/controllers/todos.js index 811dd9933b..4d642ea799 100644 --- a/architecture-examples/spine/js/controllers/todos.js +++ b/architecture-examples/spine/js/controllers/todos.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.6.2 +// Generated by CoffeeScript 1.6.3 (function() { var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = {}.hasOwnProperty, @@ -26,7 +26,8 @@ }; function Todos() { - this.render = __bind(this.render, this); Todos.__super__.constructor.apply(this, arguments); + this.render = __bind(this.render, this); + Todos.__super__.constructor.apply(this, arguments); this.todo.bind('update', this.render); this.todo.bind('destroy', this.release); } @@ -46,12 +47,11 @@ Todos.prototype.edit = function() { this.el.addClass('editing'); - return this.editElem.focus(); + return this.editElem.val(this.editElem.val()).focus(); }; Todos.prototype.finishEdit = function() { var val; - this.el.removeClass('editing'); val = $.trim(this.editElem.val()); if (val) { diff --git a/architecture-examples/spine/js/models/todo.js b/architecture-examples/spine/js/models/todo.js index 175aa60750..a49befc6de 100644 --- a/architecture-examples/spine/js/models/todo.js +++ b/architecture-examples/spine/js/models/todo.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.6.2 +// Generated by CoffeeScript 1.6.3 (function() { var _ref, __hasProp = {}.hasOwnProperty, @@ -30,7 +30,6 @@ Todo.destroyCompleted = function() { var todo, _i, _len, _ref1, _results; - _ref1 = this.completed(); _results = []; for (_i = 0, _len = _ref1.length; _i < _len; _i++) { diff --git a/architecture-examples/spine/readme.md b/architecture-examples/spine/readme.md index 5a2fb7e2d9..7a18bad8de 100644 --- a/architecture-examples/spine/readme.md +++ b/architecture-examples/spine/readme.md @@ -1,20 +1,52 @@ -# Spine.js TodoMVC app +# Spine.js TodoMVC Example +> Build Awesome JavaScript MVC Applications. -## Getting started +> _[Spine - spinejs.com](http://spinejs.com)_ -[CoffeeScript](http://coffeescript.org) is required to compile this application if you make changes to the files in the `src` folder. +## Learning Spine -### Compile +The [Spine website](http://spinejs.com) is a great resource for getting started. -Open Terminal in this folder. +Here are some links you may find helpful: -- `cake build` to compile once +* [Documentation](http://spinejs.com/docs/) +* [Step by Step Tutorials](http://spinejs.com/docs/example) +* [API Reference](http://spinejs.com/api/index) -- `cake watch` to compile on save +Articles and guides from the community: + +* [Building JavaScript Web Apps With MVC & Spine.js](http://addyosmani.com/blog/building-apps-spinejs) + +Get help from other Spine users: + +* [Spine on StackOverflow](http://stackoverflow.com/questions/tagged/spine.js) +* [Mailing list on Google Groups](https://groups.google.com/forum/#!forum/spinejs) +* [Spine's author, Alex MacCaw, on Twitter](http://twitter.com/maccman) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ + + +## Running + +This app is written in [CoffeeScript](http://coffeescript.org/). If you wish to make changes, follow these steps to re-compile the code. + +To install CoffeeScript globally: + + npm install -g coffee-script + +To compile once: + + # from architecture-examples/knockback + cake build + +To compile on save + + # from architecture-examples/knockback + cake watch ## Credit -Created by [Sindre Sorhus](https://github.com/sindresorhus) +This TodoMVC application was created by [Sindre Sorhus](https://github.com/sindresorhus). diff --git a/architecture-examples/spine/src/controllers/todos.coffee b/architecture-examples/spine/src/controllers/todos.coffee index d73f7b9c68..2473324741 100644 --- a/architecture-examples/spine/src/controllers/todos.coffee +++ b/architecture-examples/spine/src/controllers/todos.coffee @@ -29,7 +29,7 @@ class window.Todos extends Spine.Controller edit: -> @el.addClass 'editing' - @editElem.focus() + @editElem.val(@editElem.val()).focus() finishEdit: -> @el.removeClass 'editing' diff --git a/architecture-examples/yui/bower.json b/architecture-examples/yui/bower.json new file mode 100644 index 0000000000..b1a6bc4656 --- /dev/null +++ b/architecture-examples/yui/bower.json @@ -0,0 +1,7 @@ +{ + "name": "todomvc-yui", + "version": "0.0.0", + "dependencies": { + "todomvc-common": "~0.1.6" + } +} diff --git a/architecture-examples/yui/bower_components/todomvc-common/base.css b/architecture-examples/yui/bower_components/todomvc-common/base.css new file mode 100644 index 0000000000..3e6bfaf38d --- /dev/null +++ b/architecture-examples/yui/bower_components/todomvc-common/base.css @@ -0,0 +1,555 @@ +html, +body { + margin: 0; + padding: 0; +} + +button { + margin: 0; + padding: 0; + border: 0; + background: none; + font-size: 100%; + vertical-align: baseline; + font-family: inherit; + color: inherit; + -webkit-appearance: none; + /*-moz-appearance: none;*/ + -ms-appearance: none; + -o-appearance: none; + appearance: none; +} + +body { + font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; + line-height: 1.4em; + background: #eaeaea url('bg.png'); + color: #4d4d4d; + width: 550px; + margin: 0 auto; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + -ms-font-smoothing: antialiased; + -o-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +#todoapp { + background: #fff; + background: rgba(255, 255, 255, 0.9); + margin: 130px 0 40px 0; + border: 1px solid #ccc; + position: relative; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2), + 0 25px 50px 0 rgba(0, 0, 0, 0.15); +} + +#todoapp:before { + content: ''; + border-left: 1px solid #f5d6d6; + border-right: 1px solid #f5d6d6; + width: 2px; + position: absolute; + top: 0; + left: 40px; + height: 100%; +} + +#todoapp input::-webkit-input-placeholder { + font-style: italic; +} + +#todoapp input::-moz-placeholder { + font-style: italic; + color: #a9a9a9; +} + +#todoapp h1 { + position: absolute; + top: -120px; + width: 100%; + font-size: 70px; + font-weight: bold; + text-align: center; + color: #b3b3b3; + color: rgba(255, 255, 255, 0.3); + text-shadow: -1px -1px rgba(0, 0, 0, 0.2); + -webkit-text-rendering: optimizeLegibility; + -moz-text-rendering: optimizeLegibility; + -ms-text-rendering: optimizeLegibility; + -o-text-rendering: optimizeLegibility; + text-rendering: optimizeLegibility; +} + +#header { + padding-top: 15px; + border-radius: inherit; +} + +#header:before { + content: ''; + position: absolute; + top: 0; + right: 0; + left: 0; + height: 15px; + z-index: 2; + border-bottom: 1px solid #6c615c; + background: #8d7d77; + background: -webkit-gradient(linear, left top, left bottom, from(rgba(132, 110, 100, 0.8)),to(rgba(101, 84, 76, 0.8))); + background: -webkit-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8)); + background: -moz-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8)); + background: -o-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8)); + background: -ms-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8)); + background: linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8)); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670'); + border-top-left-radius: 1px; + border-top-right-radius: 1px; +} + +#new-todo, +.edit { + position: relative; + margin: 0; + width: 100%; + font-size: 24px; + font-family: inherit; + line-height: 1.4em; + border: 0; + outline: none; + color: inherit; + padding: 6px; + border: 1px solid #999; + box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + -o-box-sizing: border-box; + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + -ms-font-smoothing: antialiased; + -o-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +#new-todo { + padding: 16px 16px 16px 60px; + border: none; + background: rgba(0, 0, 0, 0.02); + z-index: 2; + box-shadow: none; +} + +#main { + position: relative; + z-index: 2; + border-top: 1px dotted #adadad; +} + +label[for='toggle-all'] { + display: none; +} + +#toggle-all { + position: absolute; + top: -42px; + left: -4px; + width: 40px; + text-align: center; + border: none; /* Mobile Safari */ +} + +#toggle-all:before { + content: '»'; + font-size: 28px; + color: #d9d9d9; + padding: 0 25px 7px; +} + +#toggle-all:checked:before { + color: #737373; +} + +#todo-list { + margin: 0; + padding: 0; + list-style: none; +} + +#todo-list li { + position: relative; + font-size: 24px; + border-bottom: 1px dotted #ccc; +} + +#todo-list li:last-child { + border-bottom: none; +} + +#todo-list li.editing { + border-bottom: none; + padding: 0; +} + +#todo-list li.editing .edit { + display: block; + width: 506px; + padding: 13px 17px 12px 17px; + margin: 0 0 0 43px; +} + +#todo-list li.editing .view { + display: none; +} + +#todo-list li .toggle { + text-align: center; + width: 40px; + /* auto, since non-WebKit browsers doesn't support input styling */ + height: auto; + position: absolute; + top: 0; + bottom: 0; + margin: auto 0; + border: none; /* Mobile Safari */ + -webkit-appearance: none; + /*-moz-appearance: none;*/ + -ms-appearance: none; + -o-appearance: none; + appearance: none; +} + +#todo-list li .toggle:after { + content: '✔'; + line-height: 43px; /* 40 + a couple of pixels visual adjustment */ + font-size: 20px; + color: #d9d9d9; + text-shadow: 0 -1px 0 #bfbfbf; +} + +#todo-list li .toggle:checked:after { + color: #85ada7; + text-shadow: 0 1px 0 #669991; + bottom: 1px; + position: relative; +} + +#todo-list li label { + word-break: break-word; + padding: 15px; + margin-left: 45px; + display: block; + line-height: 1.2; + -webkit-transition: color 0.4s; + -moz-transition: color 0.4s; + -ms-transition: color 0.4s; + -o-transition: color 0.4s; + transition: color 0.4s; +} + +#todo-list li.completed label { + color: #a9a9a9; + text-decoration: line-through; +} + +#todo-list li .destroy { + display: none; + position: absolute; + top: 0; + right: 10px; + bottom: 0; + width: 40px; + height: 40px; + margin: auto 0; + font-size: 22px; + color: #a88a8a; + -webkit-transition: all 0.2s; + -moz-transition: all 0.2s; + -ms-transition: all 0.2s; + -o-transition: all 0.2s; + transition: all 0.2s; +} + +#todo-list li .destroy:hover { + text-shadow: 0 0 1px #000, + 0 0 10px rgba(199, 107, 107, 0.8); + -webkit-transform: scale(1.3); + -moz-transform: scale(1.3); + -ms-transform: scale(1.3); + -o-transform: scale(1.3); + transform: scale(1.3); +} + +#todo-list li .destroy:after { + content: '✖'; +} + +#todo-list li:hover .destroy { + display: block; +} + +#todo-list li .edit { + display: none; +} + +#todo-list li.editing:last-child { + margin-bottom: -1px; +} + +#footer { + color: #777; + padding: 0 15px; + position: absolute; + right: 0; + bottom: -31px; + left: 0; + height: 20px; + z-index: 1; + text-align: center; +} + +#footer:before { + content: ''; + position: absolute; + right: 0; + bottom: 31px; + left: 0; + height: 50px; + z-index: -1; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3), + 0 6px 0 -3px rgba(255, 255, 255, 0.8), + 0 7px 1px -3px rgba(0, 0, 0, 0.3), + 0 43px 0 -6px rgba(255, 255, 255, 0.8), + 0 44px 2px -6px rgba(0, 0, 0, 0.2); +} + +#todo-count { + float: left; + text-align: left; +} + +#filters { + margin: 0; + padding: 0; + list-style: none; + position: absolute; + right: 0; + left: 0; +} + +#filters li { + display: inline; +} + +#filters li a { + color: #83756f; + margin: 2px; + text-decoration: none; +} + +#filters li a.selected { + font-weight: bold; +} + +#clear-completed { + float: right; + position: relative; + line-height: 20px; + text-decoration: none; + background: rgba(0, 0, 0, 0.1); + font-size: 11px; + padding: 0 10px; + border-radius: 3px; + box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.2); +} + +#clear-completed:hover { + background: rgba(0, 0, 0, 0.15); + box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.3); +} + +#info { + margin: 65px auto 0; + color: #a6a6a6; + font-size: 12px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7); + text-align: center; +} + +#info a { + color: inherit; +} + +/* + Hack to remove background from Mobile Safari. + Can't use it globally since it destroys checkboxes in Firefox and Opera +*/ +@media screen and (-webkit-min-device-pixel-ratio:0) { + #toggle-all, + #todo-list li .toggle { + background: none; + } + + #todo-list li .toggle { + height: 40px; + } + + #toggle-all { + top: -56px; + left: -15px; + width: 65px; + height: 41px; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + -webkit-appearance: none; + appearance: none; + } +} + +.hidden{ + display:none; +} + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/architecture-examples/yui/bower_components/todomvc-common/base.js b/architecture-examples/yui/bower_components/todomvc-common/base.js new file mode 100644 index 0000000000..099da60dd1 --- /dev/null +++ b/architecture-examples/yui/bower_components/todomvc-common/base.js @@ -0,0 +1,209 @@ +(function () { + 'use strict'; + + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + + if (location.hostname === 'todomvc.com') { + window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); + } + + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); + } + } + + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } + + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); + } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; + } + + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); + } + } + + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + + redirect(); + getFile('learn.json', Learn); +})(); diff --git a/architecture-examples/yui/bower_components/todomvc-common/bg.png b/architecture-examples/yui/bower_components/todomvc-common/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..b2a7600825ee11f21849ed475499c7d1ecbcc870 GIT binary patch literal 2126 zcmV-U2(kBxP)+9y`=HK7nt=~3t000O5Nklm=04hVa_lXl_bm=+M;=eI<%$rO2ta`suh*Sr#POw*?adq!O!CV z*0&b)rkCCEV)1nIuiLBntUH-MJI;&qYgz|d@Nhnn_abi2g`pu4NAMVid3hS%?quz~ zjlJf(x8cj{VS zUVEP1msg9`^OFUhSO5rtXHhRlyU2i>6$BT=glG`{JlctGHrwRIm)6Buu65jLQn^H8 zvl9lZqUBA+%qvM5XC+yY@mfA(YB~XP=e|6<{%$^eU8nrK?v2ccb@Jom5CG>rKAL7J zplHEIavVp|0p1&m!G`Ti?<7iZ;}@G7#Z)}Km%2!FHnQ0*&?PLR)G!HAaHgU#c|$dz zpj#0HmeadIe>`#)=Jjkb{B=FKnU3pc-&Y@j_j6(h4Y~+Uq!^J=LHunx1xi4QXK-Y{&MoT8ky6Vb9c|WhnOwF~c=3zOy8agktliS6# z`#8F`9H)D=bmk9B5MnW&_r#)f$c+;$LSr-@^An8dhc~Iquuv>jOK7pw7LJ;&X0i1C zGMsHdP1Os@ny$$j!>XAii%7bp5k>`pyNA!~epb)()p9zR4Yl6z=U}{CIdh1z(FpAo zQIW!;0zpCyC4*7YLkZCO@cul0R_&zghsA8Ek)z%jNpKa92{@NH+SstX%@}xB*Jk!l}PZ1cClIns~}5^!RncUk*rmA z%SIVgt58EQxLJ+OiFqKkBuwquyZLUp|gr zPUbUbFbBrPd1xO`^C*r-i3p9*F#(OBh!4Wy@aC&*!|O|GXcjDA&YhF{;cD7*o(GS^ z@pQSE7)x_81=Qyje6*LQ#TXu-7(o;S8u3tpDA0_ddj%hmCspeXdhYR}-i9A=C`EoChUYuH~^x!9+|&(Pgb*>Ck<=9j|)*@xyfT zpP#+Kt<}39b|3Wl4fxT(+G?aH>gG^d@MEaUOJRfy55TtFI7^Y)VuMU=7Pp0y55jS~ z+TJ)igMyrqkX;wU8j68iIDtqJYhS_D3_Oem-@g6me_RfiQ}uT_K-A-9qG%}gk3E9c z!8`KgsMNXm)beloPfMql*|&$M>1q`i!cY)RFYnjNYu*gSv@8XebV7%}xYL>6)GJPJ zJpA7K31lcJuIFKSw-{x4FX0K2Az)~Xg<`sOu$4|^-(^XJX4YzoiNRvL zyuY7~26w-P^Zw%6F}shBwV2$02c8RsSUy6dM92diCAxiX3IUqsq5ig6>U_!Vy*q5$ zjm}16tJr+QZ&T?HkkpeIwVX-r1EI=@%Zlt;6g*mj&E!A))%gXJ=x6u#l zcKEP>bx4rqV*k`BBrZ$Mqjt{TsHcxUH>;)iAK}B(Kila&VD%b?6m&^0WK4^&EZNAI z8AMYs_%$D%|M+@+cQqL-hi4yG>h*jwdii!W1{}p>ZhwFYt_4Su1kjY9<-5`!$VNOI1y(EDSH4WpCijE_>al!Nt=^eVER#uJ1=b z;BWF2IgyF5LexV+yec$Kin;Ai@myo;G>zJ&jrdW#ecXhIZph5OYqw_PEfcF56Z5Zu_ZZE#q3Mc+N&1O^7hoh9QR7`+L$cBP5pqG=fqA0uh zUBukaxTFmH)<|Xbvp2c=HSbNkpXw73a5lv7V$jb92#yZ141@$X?F}Jt8gIU7Wm6m9 z?e_;;zsnm6`LZeP>T=$)Kr>Z?kr*UmFqR7zx0C6^bmcsc@1AGtw_rNH>-Xm$d*|Q< zn&1Ln0u7=l&ILs>%CkJp`DiG9F18x4Ne+lg<#i?e7jL%x;4ZnRkN^Mx07*qoM6N<$ Ef(>0N!2kdN literal 0 HcmV?d00001 diff --git a/architecture-examples/yui/index.html b/architecture-examples/yui/index.html index 6008e63517..d613f5b8d6 100644 --- a/architecture-examples/yui/index.html +++ b/architecture-examples/yui/index.html @@ -1,90 +1,84 @@ - - - - - YUI • TodoMVC - - - - -
          - -
          - - -
            + + + + + YUI • TodoMVC + + + +
            + +
            + + +
              +
              +
              -
              -
              - - - - - - + + + + + - + }).use('todo-app', function (Y) { + new Y.TodoMVC.TodoApp(); + }); + + diff --git a/architecture-examples/yui/js/app.js b/architecture-examples/yui/js/app.js index df2607345d..cece5932e6 100644 --- a/architecture-examples/yui/js/app.js +++ b/architecture-examples/yui/js/app.js @@ -157,7 +157,7 @@ YUI.add('todo-app', function (Y) { var allCheckbox = this.get('allCheckbox'); var completed = allCheckbox.get('checked'); - Y.Array.each(todoList.toArray(), function (todo) { + todoList.each(function (todo) { todo.save({completed: completed}); }); }, @@ -230,7 +230,6 @@ YUI.add('todo-app', function (Y) { 'app', 'todo-list', 'todo-view', - 'node', - 'event-focus' + 'node' ] }); diff --git a/architecture-examples/yui/js/views/todoview.js b/architecture-examples/yui/js/views/todoview.js index d086acea18..36d7af8d0a 100644 --- a/architecture-examples/yui/js/views/todoview.js +++ b/architecture-examples/yui/js/views/todoview.js @@ -58,8 +58,12 @@ YUI.add('todo-view', function (Y) { // Turn on editing mode for the Todo by exposing the input field. edit: function () { + var input = this.get('inputNode'); + this.get('container').addClass('editing'); - this.get('inputNode').focus(); + // place cursor at the end of the line + input._node.value = input._node.value; + input.focus(); }, // Get the value from our input field while hiding it, and @@ -95,6 +99,7 @@ YUI.add('todo-view', function (Y) { }, '@VERSION@', { requires: [ 'view', - 'handlebars' + 'handlebars', + 'event-focus' ] }); diff --git a/architecture-examples/yui/readme.md b/architecture-examples/yui/readme.md new file mode 100644 index 0000000000..f8dc115212 --- /dev/null +++ b/architecture-examples/yui/readme.md @@ -0,0 +1,26 @@ +# YUI TodoMVC Example + +> YUI is a free, open source JavaScript and CSS library for building richly interactive web applications. + +> _[YUI - yuilibrary.com](http://yuilibrary.com)_ + + +## Learning YUI + +The [YUI website](http://yuilibrary.com) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Documentation](http://yuilibrary.com/yui/docs) +* [Quick Start](http://yuilibrary.com/yui/quick-start) +* [Tutorials](http://yuilibrary.com/yui/docs/tutorials) +* [Examples](http://yuilibrary.com/yui/docs/examples) +* [Blog](http://yuiblog.com) + +Get help from other YUI users: + +* [YUI on StackOverflow](http://stackoverflow.com/questions/tagged/yui) +* [Forms](http://yuilibrary.com/forum) +* [YUI on Twitter](http://twitter.com/yuilibrary) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ diff --git a/assets/base.css b/assets/base.css index 8d1db3a696..5699989b29 100644 --- a/assets/base.css +++ b/assets/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } diff --git a/assets/base.js b/assets/base.js index 9d411e6840..4da326723e 100644 --- a/assets/base.js +++ b/assets/base.js @@ -2,13 +2,12 @@ 'use strict'; if (location.hostname === 'todomvc.com') { - window._gaq=[['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); + window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); } function getSourcePath() { - // If accessed via addyosmani.github.com/todomvc/, strip the project - // path. - if (location.hostname.indexOf('github.com') > 0) { + // If accessed via tastejs.github.io/todomvc/, strip the project path. + if (location.hostname.indexOf('github.io') > 0) { return location.pathname.replace(/todomvc\//, ''); } return location.pathname; @@ -18,7 +17,7 @@ var sourceLink = document.createElement('a'); var paragraph = document.createElement('p'); var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; + var urlBase = 'https://github.com/tastejs/todomvc/tree/gh-pages'; if (footer) { sourceLink.href = urlBase + getSourcePath(); @@ -29,9 +28,8 @@ } function redirect() { - if (location.hostname === 'addyosmani.github.com') { - location.href = location.href.replace('addyosmani.github.com/todomvc', - 'todomvc.com'); + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); } } diff --git a/changelog.md b/changelog.md index 5ab82489a9..9b6a862d1d 100644 --- a/changelog.md +++ b/changelog.md @@ -1,20 +1,27 @@ # Changelog -## 1.2 - TBA +## 1.2 - 2013-08-06 - New since 1.1: + - Polymer - Flight - DeftJS + ExtJS - Aria Templates - Enyo + Backbone.js + - React + - SAPUI5 + - AngularJS + Firebase - Updates since 1.1: - Backbone 1.0 + - cujoJS got updated - Kendo UI Spring 2013 release - Maria graduated from labs + - TroopJS 2.0 - The GWT example implemented routing - The sammy.js example implemented routing +- Removed Ember.js + require.js example ## 1.1 - 2013-02-14 diff --git a/codestyle.md b/codestyle.md index bba3b796a1..21fa36d274 100644 --- a/codestyle.md +++ b/codestyle.md @@ -1,7 +1,10 @@ # Code Style + We think it's best for the project if the code you write looks like the code the last developer wrote. Please read this document in its entirety, and be sure to refer back to it throughout the development of your contribution. We greatly appreciate your cooperation. + ## General Rules + - Tab indentation - Single-quotes - Semicolon @@ -20,26 +23,28 @@ Example: 'use strict'; function foo(bar, fum) { - var i, l, ret; - var hello = 'Hello'; + var i, l, ret; + var hello = 'Hello'; - if (!bar) { - return; - } + if (!bar) { + return; + } - for (i = 0, l = bar.length; i < l; i++) { - if (bar[i] === hello) { - ret += fum(bar[i]); - } - } + for (i = 0, l = bar.length; i < l; i++) { + if (bar[i] === hello) { + ret += fum(bar[i]); + } + } - return ret; + return ret; } ``` Read [idiomatic.js](https://github.com/rwldrn/idiomatic.js) for general JavaScript code style best practices. + ## Anonymous Functions + When using anonymous functions, leave a space between the function name and opening parenthesis. Example: @@ -52,7 +57,9 @@ Example: }) ``` + ## Comments + Inline comments are a great way of giving new users a better understanding of what you're doing and why. It's also helpful to let your functions breathe, by leaving additional lines between statements. @@ -81,6 +88,7 @@ var removeTodo = function (todoItem) { ``` ## RequireJS + When using RequireJS, please format your code to these specifications: ```js @@ -95,6 +103,7 @@ define('Block', [ ``` ## JSHint + When you submit your pull request, one of the first things we will do is run JSHint against your code. You can help speed the process by running it yourself: diff --git a/contributing.md b/contributing.md index 7ab5bc9faf..0a2e43415d 100644 --- a/contributing.md +++ b/contributing.md @@ -5,7 +5,7 @@ We're happy to accept contributions in the form of new apps, bug fixes, issues, ## Code Style -We think it's best for the project if the code you write looks like the code the last developer wrote, so we've put together [some guidelines we ask that you follow](https://github.com/addyosmani/todomvc/tree/gh-pages/codestyle.md). We greatly appreciate your cooperation and contribution. +We think it's best for the project if the code you write looks like the code the last developer wrote, so we've put together [some guidelines we ask that you follow](https://github.com/tastejs/todomvc/tree/gh-pages/codestyle.md). We greatly appreciate your cooperation and contribution. ## Pull Request Guidelines @@ -17,9 +17,9 @@ We think it's best for the project if the code you write looks like the code the ## Submitting a New App -- **Read the [App Specification](https://github.com/addyosmani/todomvc/wiki/App-Specification) thoroughly** +- **Read the [App Specification](https://github.com/tastejs/todomvc/wiki/App-Specification) thoroughly** - Make sure it hasn't already been submitted or declined by searching the issue tracker -- Looking at our most recent [reference app](https://github.com/addyosmani/todomvc/tree/gh-pages/architecture-examples/backbone) +- Looking at our most recent [reference app](https://github.com/tastejs/todomvc/tree/gh-pages/architecture-examples/backbone) One of us will be happy to review your submission and discuss any changes that may be required before it can be included. Apps will typically land first in Labs, reaching the 'stable' mark once we and the community are happy with it. @@ -42,4 +42,4 @@ If you are a library author or contributor wishing to start work on writing test Note that due to the current number of MVC/MVVM/MV* frameworks in circulation, it's not always possible to include each one in TodoMVC, but we'll definitely discuss the merits of any framework prior to making a decision :) -For applications that we feel don't quite match the goals of the project, but which we feel still offer value, we're happy to include references to them in our official [wiki](https://github.com/addyosmani/todomvc/wiki/Other-implementations). +For applications that we feel don't quite match the goals of the project, but which we feel still offer value, we're happy to include references to them in our official [wiki](https://github.com/tastejs/todomvc/wiki/Other-implementations). diff --git a/dependency-examples/backbone_require/bower_components/todomvc-common/base.css b/dependency-examples/backbone_require/bower_components/todomvc-common/base.css index 8d1db3a696..3e6bfaf38d 100644 --- a/dependency-examples/backbone_require/bower_components/todomvc-common/base.css +++ b/dependency-examples/backbone_require/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -412,3 +412,144 @@ label[for='toggle-all'] { .hidden{ display:none; } + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/dependency-examples/backbone_require/bower_components/todomvc-common/base.js b/dependency-examples/backbone_require/bower_components/todomvc-common/base.js index 3fd166d061..099da60dd1 100644 --- a/dependency-examples/backbone_require/bower_components/todomvc-common/base.js +++ b/dependency-examples/backbone_require/bower_components/todomvc-common/base.js @@ -1,38 +1,209 @@ (function () { 'use strict'; + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + if (location.hostname === 'todomvc.com') { window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); } - function getSourcePath() { - // If accessed via addyosmani.github.io/todomvc/, strip the project path. - if (location.hostname.indexOf('github.io') > 0) { - return location.pathname.replace(/todomvc\//, ''); + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); } - return location.pathname; } - function appendSourceLink() { - var sourceLink = document.createElement('a'); - var paragraph = document.createElement('p'); - var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } - if (footer) { - sourceLink.href = urlBase + getSourcePath(); - sourceLink.appendChild(document.createTextNode('Check out the source')); - paragraph.appendChild(sourceLink); - footer.appendChild(paragraph); + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; } - function redirect() { - if (location.hostname === 'addyosmani.github.io') { - location.href = location.href.replace('addyosmani.github.io/todomvc', 'todomvc.com'); + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); } } - appendSourceLink(); + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + redirect(); + getFile('learn.json', Learn); })(); diff --git a/dependency-examples/backbone_require/index.html b/dependency-examples/backbone_require/index.html index eb30a0ebc7..da4e55be98 100644 --- a/dependency-examples/backbone_require/index.html +++ b/dependency-examples/backbone_require/index.html @@ -1,30 +1,30 @@ - - - - - Backbone.js + RequireJS • TodoMVC - - - - -
              - -
              - - -
                + + + + + Backbone.js + RequireJS • TodoMVC + + + + +
                + +
                + + +
                  +
                  +
                  -
                  -
                  - - - + + + diff --git a/dependency-examples/backbone_require/readme.md b/dependency-examples/backbone_require/readme.md new file mode 100644 index 0000000000..fdb149bfea --- /dev/null +++ b/dependency-examples/backbone_require/readme.md @@ -0,0 +1,29 @@ +# Backbone.js & RequireJS TodoMVC Example + +> Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface. + +> _[Backbone.js - backbonejs.org](http://backbonejs.org)_ + + +## Learning Backbone.js + +The [Backbone.js website](http://backbonejs.org) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Annotated source code](http://backbonejs.org/docs/backbone.html) +* [Applications built with Backbone.js](http://backbonejs.org/#examples) +* [FAQ](http://backbonejs.org/#faq) + +Articles and guides from the community: + +* [Developing Backbone.js Applications](http://addyosmani.github.io/backbone-fundamentals) +* [Collection of tutorials, blog posts, and example sites](https://github.com/documentcloud/backbone/wiki/Tutorials%2C-blog-posts-and-example-sites) + +Get help from other Backbone.js users: + +* [Backbone.js on StackOverflow](http://stackoverflow.com/questions/tagged/backbone.js) +* [Google Groups mailing list](https://groups.google.com/forum/#!forum/backbonejs) +* [Backbone.js on Twitter](http://twitter.com/documentcloud) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ diff --git a/dependency-examples/emberjs_require/css/app.css b/dependency-examples/emberjs_require/css/app.css deleted file mode 100644 index 885f19d3de..0000000000 --- a/dependency-examples/emberjs_require/css/app.css +++ /dev/null @@ -1,131 +0,0 @@ -/* Mocha */ - -#mocha h1, h2 { - margin: 0; -} - -#mocha h1 { - font-size: 1em; - font-weight: 200; -} - -#mocha .suite .suite h1 { - font-size: .8em; -} - -#mocha h2 { - font-size: 12px; - font-weight: normal; - cursor: pointer; -} - -#mocha .suite { - margin-left: 15px; -} - -#mocha .test { - margin-left: 15px; -} - -#mocha .test:hover h2::after { - position: relative; - top: 0; - right: -10px; - content: '(view source)'; - font-size: 12px; - font-family: arial; - color: #888; -} - -#mocha .test.pending:hover h2::after { - content: '(pending)'; - font-family: arial; -} - -#mocha .test.pass::before { - content: '✓'; - font-size: 12px; - display: block; - float: left; - margin-right: 5px; - color: #00c41c; -} - -#mocha .test.pending { - color: #0b97c4; -} - -#mocha .test.pending::before { - content: '◦'; - color: #0b97c4; -} - -#mocha .test.fail { - color: #c00; -} - -#mocha .test.fail pre { - color: black; -} - -#mocha .test.fail::before { - content: '✖'; - font-size: 12px; - display: block; - float: left; - margin-right: 5px; - color: #c00; -} - -#mocha .test pre.error { - color: #c00; -} - -#mocha .test pre { - display: inline-block; - font: 12px/1.5 monaco, monospace; - margin: 5px; - padding: 15px; - border: 1px solid #eee; - border-bottom-color: #ddd; - -webkit-border-radius: 3px; - -webkit-box-shadow: 0 1px 3px #eee; -} - -#error { - color: #c00; - font-size: 1.5 em; - font-weight: 100; - letter-spacing: 1px; -} - -#stats { - position: fixed; - top: 15px; - right: 10px; - font-size: 12px; - margin: 0; - color: #888; -} - -#stats .progress { - float: right; - padding-top: 0; -} - -#stats em { - color: black; -} - -#stats li { - display: inline-block; - margin: 0 5px; - list-style: none; - padding-top: 11px; -} - -code .comment { color: #ddd } -code .init { color: #2F6FAD } -code .string { color: #5890AD } -code .keyword { color: #8A6343 } -code .number { color: #2F6FAD } diff --git a/dependency-examples/emberjs_require/index.html b/dependency-examples/emberjs_require/index.html index b088d15713..b32a379166 100644 --- a/dependency-examples/emberjs_require/index.html +++ b/dependency-examples/emberjs_require/index.html @@ -1,28 +1,3 @@ - - - - - ember.js + require.js • TodoMVC - - - - - - -
                  - - - - - +ember.js + require.js • TodoMVC + diff --git a/dependency-examples/emberjs_require/js/app.js b/dependency-examples/emberjs_require/js/app.js deleted file mode 100644 index cb03680fdf..0000000000 --- a/dependency-examples/emberjs_require/js/app.js +++ /dev/null @@ -1,43 +0,0 @@ -// Define libraries -require.config({ - baseUrl: 'js/', - paths: { - jquery: '../../../assets/jquery.min', - ember: 'lib/ember-latest.min', - handlebars: '../../../assets/handlebars.min', - text: 'lib/require/text', - jasmine: '../../../assets/jasmine/jasmine', - jasmine_html: '../../../assets/jasmine/jasmine-html' - } -}); - -// Load our app -define( 'app', [ - 'app/router', - 'app/models/store', - 'app/controllers/entries', - 'app/views/application', - 'jquery', - 'handlebars', - 'ember' - ], function( Router, Store, EntriesController, ApplicationView ) { - var App = Ember.Application.create({ - VERSION: '1.0', - rootElement: '#todoapp', - // Load routes - Router: Router, - // Extend to inherit outlet support - ApplicationController: Ember.Controller.extend(), - ApplicationView: ApplicationView, - entriesController: EntriesController.create({ - store: new Store('todos-emberjs') - }), - ready: function() { - this.initialize(); - } - }); - - // Expose the application globally - return window.Todos = App; - } -); diff --git a/dependency-examples/emberjs_require/js/app/controllers/entries.js b/dependency-examples/emberjs_require/js/app/controllers/entries.js deleted file mode 100644 index 05d770a505..0000000000 --- a/dependency-examples/emberjs_require/js/app/controllers/entries.js +++ /dev/null @@ -1,72 +0,0 @@ -define('app/controllers/entries', [ 'ember' ], - /** - * Entries controller - * - * @returns Class - */ - function() { - return Ember.ArrayProxy.extend({ - store: null, - content: [], - - createNew: function( value ) { - if ( !value.trim() ) - return; - var todo = this.get( 'store' ).createFromTitle( value ); - this.pushObject( todo ); - }, - - pushObject: function( item, ignoreStorage) { - if ( !ignoreStorage ) - this.get( 'store' ).create( item ); - return this._super( item ); - }, - - removeObject: function( item ) { - this.get( 'store' ).remove( item ); - return this._super( item ); - }, - - clearCompleted: function() { - this.filterProperty( - 'completed', true - ).forEach( this.removeObject, this ); - }, - - total: function() { - return this.get( 'length' ); - }.property( '@each.length' ), - - remaining: function() { - return this.filterProperty( 'completed', false ).get( 'length' ); - }.property( '@each.completed' ), - - completed: function() { - return this.filterProperty( 'completed', true ).get( 'length' ); - }.property( '@each.completed' ), - - noneLeft: function() { - return this.get( 'total' ) === 0; - }.property( 'total' ), - - allAreDone: function( key, value ) { - if ( value !== undefined ) { - this.setEach( 'completed', value ); - return value; - } else { - return !!this.get( 'length' ) && - this.everyProperty( 'completed', true ); - } - }.property( '@each.completed' ), - - init: function() { - this._super(); - // Load items if any upon initialization - var items = this.get( 'store' ).findAll(); - if ( items.get( 'length' ) ) { - this.set( '[]', items ); - }; - } - }); - } -); diff --git a/dependency-examples/emberjs_require/js/app/controllers/todos.js b/dependency-examples/emberjs_require/js/app/controllers/todos.js deleted file mode 100644 index 0bf574e75d..0000000000 --- a/dependency-examples/emberjs_require/js/app/controllers/todos.js +++ /dev/null @@ -1,27 +0,0 @@ -define('app/controllers/todos', [ 'ember' ], - /** - * Todos controller - * - * @returns Class - */ - function() { - return Ember.Controller.extend({ - entries: function() { - var filter = this.getPath( 'content.filterBy' ); - - if ( Ember.empty( filter ) ) { - return this.get( 'content' ); - } - - if ( !Ember.compare( filter, 'completed' ) ) { - return this.get( 'content' ).filterProperty( 'completed', true ); - } - - if ( !Ember.compare( filter, 'active' ) ) { - return this.get( 'content' ).filterProperty( 'completed', false ); - } - - }.property( 'content.remaining' ) - }); - } -); diff --git a/dependency-examples/emberjs_require/js/app/models/store.js b/dependency-examples/emberjs_require/js/app/models/store.js deleted file mode 100644 index 3bd0339207..0000000000 --- a/dependency-examples/emberjs_require/js/app/models/store.js +++ /dev/null @@ -1,80 +0,0 @@ -define('app/models/store', [ - 'app/models/todo', - 'ember' - ], - /** - * Todo entries storage model - * - * @param Class Todo, the todo entry model - * @returns Class - */ - function( Todo ) { - // Our Store is represented by a single JS object in *localStorage*. - // Create it with a meaningful name, like the name you'd give a table. - return function( name ) { - this.name = name; - var store = localStorage.getItem( this.name ); - this.data = ( store && JSON.parse( store ) ) || {}; - - // Save the current state of the **Store** to *localStorage*. - this.save = function() { - localStorage.setItem( this.name, JSON.stringify( this.data ) ); - }; - - // Wrapper around `this.create` - // Creates a `Todo` model object out of the title - this.createFromTitle = function( title ) { - var todo = Todo.create({ - title: title, - store: this - }); - this.create( todo ); - return todo; - }; - - // Store the model inside the `Store` - this.create = function ( model ) { - if ( !model.get( 'id' ) ) - model.set( 'id', Date.now() ); - return this.update( model ); - }; - - // Update a model by replacing its copy in `this.data`. - this.update = function( model ) { - this.data[ model.get( 'id' ) ] = model.getProperties( - 'id', 'title', 'completed' - ); - this.save(); - return model; - }; - - // Retrieve a model from `this.data` by id. - this.find = function( model ) { - var todo = Todo.create( this.data[ model.get( 'id' ) ] ); - todo.set( 'store', this ); - return todo; - }; - - // Return the array of all models currently in storage. - this.findAll = function() { - var result = [], - key; - - for ( key in this.data ) { - var todo = Todo.create( this.data[ key ] ); - todo.set( 'store', this ); - result.push( todo ); - } - - return result; - }; - - // Delete a model from `this.data`, returning it. - this.remove = function( model ) { - delete this.data[ model.get( 'id' ) ]; - this.save(); - return model; - }; - }; - } -); diff --git a/dependency-examples/emberjs_require/js/app/models/todo.js b/dependency-examples/emberjs_require/js/app/models/todo.js deleted file mode 100644 index de1cb772b6..0000000000 --- a/dependency-examples/emberjs_require/js/app/models/todo.js +++ /dev/null @@ -1,20 +0,0 @@ -define('app/models/todo', ['ember'], - /** - * Todo entry model - * - * @returns Class - */ - function() { - return Ember.Object.extend({ - id: null, - title: null, - completed: false, - // set store reference upon creation instead of creating static bindings - store: null, - // Observer that will react on item change and will update the storage - todoChanged: function() { - this.get( 'store' ).update( this ); - }.observes( 'title', 'completed' ) - }); - } -); diff --git a/dependency-examples/emberjs_require/js/app/router.js b/dependency-examples/emberjs_require/js/app/router.js deleted file mode 100644 index e94b049310..0000000000 --- a/dependency-examples/emberjs_require/js/app/router.js +++ /dev/null @@ -1,93 +0,0 @@ -define('app/router', [ 'ember' ], - /** - * Todos Router - * - * Defined routes represent filters according to specs - * - * @returns Class - */ - function() { - return Ember.Router.extend({ - - root: Ember.Route.extend({ - - showAll: Ember.Route.transitionTo( 'index' ), - showActive: Ember.Route.transitionTo( 'active' ), - showCompleted: Ember.Route.transitionTo( 'completed' ), - - index: Ember.Route.extend({ - route: '/', - connectOutlets: function( router ) { - var controller = router.get( 'applicationController' ); - var context = controller.namespace.entriesController; - context.set( 'filterBy', '' ); - - // This require was left here exclusively for design purposes - // Loads decoupled controller/view based on current route - require([ 'app/controllers/todos', 'app/views/items' ], - function( TodosController, ItemsView ) { - controller.connectOutlet({ - viewClass: ItemsView, - controller: TodosController.create(), - context: context - }); - } - ); - - } - }), - - active: Ember.Route.extend({ - route: '/active', - connectOutlets: function( router ) { - var controller = router.get( 'applicationController' ); - var context = controller.namespace.entriesController; - context.set( 'filterBy', 'active' ); - - // This require was left here exclusively for design purposes - // Loads decoupled controller/view based on current route - require([ 'app/controllers/todos', 'app/views/items' ], - function( TodosController, ItemsView ) { - controller.connectOutlet({ - viewClass: ItemsView, - controller: TodosController.create(), - context: context - }); - } - ); - - } - }), - - completed: Ember.Route.extend({ - route: '/completed', - connectOutlets: function( router ) { - var controller = router.get( 'applicationController' ); - var context = controller.namespace.entriesController; - context.set( 'filterBy', 'completed' ); - - // This require was left here exclusively for design purposes - // Loads decoupled controller/view based on current route - require([ 'app/controllers/todos', 'app/views/items' ], - function( TodosController, ItemsView ) { - controller.connectOutlet({ - viewClass: ItemsView, - controller: TodosController.create(), - context: context - }); - } - ); - - } - }), - - specs: Ember.Route.extend({ - route: '/specs', - connectOutlets: function() { - require( [ 'app/specs/helper' ] ); - } - }) - }) - }); - } -); diff --git a/dependency-examples/emberjs_require/js/app/specs/controllers/todos.js b/dependency-examples/emberjs_require/js/app/specs/controllers/todos.js deleted file mode 100644 index 54ac828853..0000000000 --- a/dependency-examples/emberjs_require/js/app/specs/controllers/todos.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Some smoke tests - */ -describe( 'controllers/todos', function() { - - var controller = Todos.get( 'todosController' ); - var title = 'Another title...'; - - it( 'should have an input for entering new entry', function() { - expect( controller.inputView ).to.be.a( 'object' ); - expect( - $( controller.inputView.get( 'element' ) ).attr( 'placeholder' ) - ).to.equal( controller.inputView.get( 'placeholder' ) ); - }); - - it( 'should not create new entry on empty-ish input', function() { - var counted = controller.get( 'remaining' ); - controller.inputView.set( 'value', ' ' ); - controller.inputView.insertNewline(); - expect( controller.get( 'remaining' ) ).to.equal( counted ) - }); - - it( 'should create new entry on newline', function() { - controller.inputView.set( 'value', title ); - controller.inputView.insertNewline(); - expect( controller.get( 'lastObject' ).title ).to.equal( title ); - controller.removeObject( controller.get( 'lastObject' ) ); - }); - - it( 'should delete item if title is empty-ish', function() { - controller.createNew( title ); - var counted = controller.get( 'remaining' ); - var entry = controller.get( 'lastObject' ); - entry.set( 'title', ' ' ); - var editor = controller.todoEditor.create({ - todo: entry, - storage: controller - }); - editor.whenDone(); - expect( controller.get( 'remaining' ) ).to.equal( counted - 1 ); - }); - - it( 'should reflect the same number of items as in store', function() { - controller.createNew( 'value', title ); - var visibles = controller.todosView. - get( 'childViews' )[ 0 ].get( 'childViews' ).length; - expect( controller.get( 'content' ).length ).to.equal( visibles ); - controller.removeObject( controller.get( 'lastObject' ) ); - }); - - it( 'should allow removing entries', function( done ) { - controller.createNew( 'value', title ); - setTimeout( function(){ - controller.allDoneCheckbox.set( 'value', true ); - }, 100 ); - setTimeout( function(){ - controller.clearCompletedButton.triggerAction(); - }, 200 ); - setTimeout( function(){ - expect( controller.get( 'content' ).length ).to.equal( 0 ); - }, 300 ); - done(); - }); - -}); diff --git a/dependency-examples/emberjs_require/js/app/specs/helper.js b/dependency-examples/emberjs_require/js/app/specs/helper.js deleted file mode 100644 index d2a0a2d32a..0000000000 --- a/dependency-examples/emberjs_require/js/app/specs/helper.js +++ /dev/null @@ -1,16 +0,0 @@ -define( 'app/specs/helper', [ 'jasmine', 'jasmine_html' ], - /** - * Specs Runner - */ - function() { - // Load testsuite - require([ - 'app/specs/todoMVC', - ], function() { - var jasmineEnv = jasmine.getEnv(); - var htmlReporter = new jasmine.HtmlReporter(); - jasmineEnv.addReporter( htmlReporter ); - jasmineEnv.execute(); - }); - } -); diff --git a/dependency-examples/emberjs_require/js/app/specs/models/store.js b/dependency-examples/emberjs_require/js/app/specs/models/store.js deleted file mode 100644 index da4cc515f0..0000000000 --- a/dependency-examples/emberjs_require/js/app/specs/models/store.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Some integration tests - */ -describe( 'models/store', function() { - - var title = 'Testing title...'; - var store = Todos.todosController.get( 'store' ); - - it( 'should allow creating and removing items', function() { - var count = store.findAll().length; - var todo = store.createFromTitle( title ); - expect( store.findAll().length ).to.equal( count + 1 ); - expect( todo ).to.have.property( 'title', title ); - expect( todo ).to.have.property( 'completed', false ); - expect( todo ).to.have.property( 'store', store ); - store.remove( todo ); - expect( store.findAll().length ).to.equal( count ); - }); - - it( 'should allow finding and changing items', function() { - var todo = store.createFromTitle( title ); - expect( store.find( todo ).id ).to.equal( todo.id ); - expect( store.find( todo ).title ).to.equal( todo.title ); - expect( store.find( todo ).completed ).to.equal( false ); - todo.set( 'completed', true ); - expect( store.find( todo ).id ).to.equal( todo.id ); - expect( store.find( todo ).completed ).to.equal( true ); - store.remove( todo ); - }); - -}); diff --git a/dependency-examples/emberjs_require/js/app/specs/todoMVC.js b/dependency-examples/emberjs_require/js/app/specs/todoMVC.js deleted file mode 100644 index 987585cf5c..0000000000 --- a/dependency-examples/emberjs_require/js/app/specs/todoMVC.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * TodoMVC Project Specs - * - * Use `runs` and `waits` to make sure results are run synchroneously - */ - -describe( 'TodoMVC features.', function(){ - - var enterEvent = $.Event('keyup', { keyCode: 13 }); - var todoTitle = 'Foo Bar Todo'; - - describe( 'Todo creation:', function() { - - beforeEach( function(){ - // Make sure we are always on the main screen - window.location.hash = '#/'; - }); - - it( 'should allow creating a new todo' , function() { - runs( function(){ - $( '#new-todo' ).val( todoTitle ).trigger( enterEvent ); - }); - - waits( 100 ); - - runs( function() { - !!$( '#todo-list li' ).text().match( todoTitle ); - }); - }); - - it( 'should not allow adding an empty todo' , function() { - var ourTodo, - beforeCount = $( '#todo-list li' ).length; - - runs( function(){ - $( '#new-todo' ).val( ' ' ).trigger( enterEvent ); - }); - - waits( 100 ); - - runs( function(){ - expect( $( '#todo-list li' ).length ).toEqual( beforeCount ); - }); - }); - }); - - describe( 'Todo completion:', function() { - it( 'should allow marking a todo complete' , function() { - var ourTodo, - beforeCount = $( '#todo-list li.completed' ).length, - postTitle = ' to be completed'; - - runs( function(){ - $( '#new-todo' ).val( todoTitle + postTitle ).trigger( enterEvent ); - }); - - waits( 100 ); - - runs( function() { - ourTodo = $( '#todo-list li:last-child' ); - - expect( ourTodo.text() ).toMatch( postTitle ); - ourTodo.find( '.toggle' ).click(); - expect( $( '#todo-list li.completed' ).length ).toEqual( beforeCount + 1 ); - }); - }); - - it( 'should allow clearing completed todos' , function() { - var ourTodo, - beforeCount = $( '#todo-list li.completed' ).length, - postTitle = ' to be completed'; - - runs( function(){ - $( '#new-todo' ).val( todoTitle + postTitle ).trigger( enterEvent ); - }); - - waits( 100 ); - - runs( function() { - ourTodo = $( '#todo-list li:last-child' ); - - expect( ourTodo.text() ).toMatch( postTitle ); - ourTodo.find( '.toggle' ).click(); - $( '#clear-completed' ).click(); - expect( $( '#todo-list li.completed' ).length ).toEqual( 0 ); - }); - }); - }); - - describe( 'Todo deletion:', function() { - it( 'should allow deleting a todo' , function() { - var ourTodo, - beforeCount = $( '#todo-list li' ).length, - postTitle = ' to be deleted'; - - runs( function(){ - $( '#new-todo' ).val( todoTitle + postTitle ).trigger( enterEvent ); - }); - - waits( 100 ); - - runs( function() { - ourTodo = $( '#todo-list li:last-child' ); - - expect( ourTodo.text() ).toMatch( postTitle ); - ourTodo.find( '.destroy' ).click(); - expect( $( '#todo-list li' ).length ).toEqual( beforeCount ); - }); - }); - }); - -}); diff --git a/dependency-examples/emberjs_require/js/app/specs/views/basic_acceptance.js b/dependency-examples/emberjs_require/js/app/specs/views/basic_acceptance.js deleted file mode 100644 index 77557bcefb..0000000000 --- a/dependency-examples/emberjs_require/js/app/specs/views/basic_acceptance.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Some acceptance testing for views - */ - -describe( 'views/*', function() { - - it( 'should validate clear button view', function( done ) { - require( [ 'text!app/views/clear_button.html' ], function( html ){ - expect( html ).to.be.a( 'string' ); - expect( html ).to.match( /completedCount/ ); - expect( function(){ Em.Handlebars.compile( html ) } ).to.not.throw( Error ); - done(); - }); - }); - - it( 'should validate items view', function( done ) { - require( [ 'text!app/views/items.html' ], function( html ) { - expect( html ).to.be.a( 'string' ); - expect( html ).to.match( /collection/ ); - expect( html ).to.match( /id="todo-list"/ ); - expect( html ).to.match( /Todos\.todosController/ ); - expect( html ).to.match( /Checkbox/ ); - expect( html ).to.match( /class="toggle"/ ); - expect( function(){ Em.Handlebars.compile( html ) } ).to.not.throw( Error ); - done(); - }); - }); - -}); diff --git a/dependency-examples/emberjs_require/js/app/templates/clear_button.html b/dependency-examples/emberjs_require/js/app/templates/clear_button.html deleted file mode 100644 index 0d398390b1..0000000000 --- a/dependency-examples/emberjs_require/js/app/templates/clear_button.html +++ /dev/null @@ -1,5 +0,0 @@ -{{#with view}} - -{{/with}} diff --git a/dependency-examples/emberjs_require/js/app/templates/filters.html b/dependency-examples/emberjs_require/js/app/templates/filters.html deleted file mode 100644 index 52e8a8f6f8..0000000000 --- a/dependency-examples/emberjs_require/js/app/templates/filters.html +++ /dev/null @@ -1,11 +0,0 @@ - diff --git a/dependency-examples/emberjs_require/js/app/templates/items.html b/dependency-examples/emberjs_require/js/app/templates/items.html deleted file mode 100644 index 588ef6a49d..0000000000 --- a/dependency-examples/emberjs_require/js/app/templates/items.html +++ /dev/null @@ -1,7 +0,0 @@ -{{#unless view.content.editing}} - {{view Ember.Checkbox checkedBinding="view.content.completed" class="toggle"}} - - -{{else}} - {{view view.ItemEditorView contentBinding="view.content"}} -{{/unless}} diff --git a/dependency-examples/emberjs_require/js/app/templates/stats.html b/dependency-examples/emberjs_require/js/app/templates/stats.html deleted file mode 100644 index 75b3c30057..0000000000 --- a/dependency-examples/emberjs_require/js/app/templates/stats.html +++ /dev/null @@ -1,7 +0,0 @@ -{{#with view}} - {{#if oneLeft }} - {{entries.remaining}} item left - {{else}} - {{entries.remaining}} items left - {{/if}} -{{/with}} diff --git a/dependency-examples/emberjs_require/js/app/views/application.js b/dependency-examples/emberjs_require/js/app/views/application.js deleted file mode 100644 index 4736f4f2e7..0000000000 --- a/dependency-examples/emberjs_require/js/app/views/application.js +++ /dev/null @@ -1,69 +0,0 @@ -define('app/views/application', [ - 'app/views/stats', - 'app/views/filters', - 'app/views/clear_button', - 'ember' - ], - /** - * Main application view - * - * @param Class StatsView, stats view class - * @param Class FiltersView, filters view class - * @param Class ClearBtnView, clear button view class - * @returns Class - */ - function( StatsView, FiltersView, ClearBtnView ) { - return Ember.ContainerView.extend({ - childViews: [ 'headerView', 'mainView', 'footerView' ], - headerView: Ember.ContainerView.create({ - childViews: [ 'titleView', 'createTodoView' ], - elementId: 'header', - tagName: 'header', - titleView: Ember.View.create({ - tagName: 'h1', - template: function() { - return 'todos'; - } - }), - createTodoView: Ember.TextField.create({ - entriesBinding: 'controller.namespace.entriesController', - placeholder: 'What needs to be done?', - elementId: 'new-todo', - insertNewline: function() { - var value = this.get( 'value' ); - if ( value ) { - this.get( 'entries' ).createNew( value ); - this.set( 'value', '' ); - } - } - }), - }), - mainView: Em.ContainerView.create({ - elementId: 'main', - tagName: 'section', - visibilityBinding: 'controller.namespace.entriesController.noneLeft', - classNameBindings: [ 'visibility:hidden' ], - childViews: [ 'outletView', 'markAllChkbox' ], - outletView: Ember.View.create({ - template: Ember.Handlebars.compile( '{{outlet}}' ), - }), - markAllChkbox: Ember.Checkbox.create({ - entriesBinding: 'controller.namespace.entriesController', - elementId: 'toggle-all', - checkedBinding: 'entries.allAreDone' - }) - }), - footerView: Ember.ContainerView.create({ - elementId: 'footer', - tagName: 'footer', - visibilityBinding: 'controller.namespace.entriesController.noneLeft', - classNameBindings: [ 'visibility:hidden' ], - childViews: [ - StatsView.create(), - FiltersView.create(), - ClearBtnView.create() - ] - }) - }) - } -); diff --git a/dependency-examples/emberjs_require/js/app/views/clear_button.js b/dependency-examples/emberjs_require/js/app/views/clear_button.js deleted file mode 100644 index 6f6aff6675..0000000000 --- a/dependency-examples/emberjs_require/js/app/views/clear_button.js +++ /dev/null @@ -1,22 +0,0 @@ -define('app/views/clear_button', [ - 'text!app/templates/clear_button.html', - 'ember' - ], - /** - * View to clear completed tasks - * - * @param String button_html, the html for view - * @returns Class - */ - function( button_html ) { - return Ember.View.extend({ - entriesBinding: 'controller.namespace.entriesController', - template: Ember.Handlebars.compile( button_html ), - classNameBindings: 'buttonClass', - buttonClass: function () { - if ( !this.getPath( 'entries.completed' ) ) - return 'hidden'; - }.property( 'entries.completed' ) - }) - } -); diff --git a/dependency-examples/emberjs_require/js/app/views/filters.js b/dependency-examples/emberjs_require/js/app/views/filters.js deleted file mode 100644 index b6435f51f4..0000000000 --- a/dependency-examples/emberjs_require/js/app/views/filters.js +++ /dev/null @@ -1,26 +0,0 @@ -define('app/views/filters', [ - 'text!app/templates/filters.html', - 'ember' - ], - /** - * View to render filter links - * - * @param String filters_html, filter links html view - * @returns Class - */ - function( filters_html ) { - return Ember.View.extend({ - template: Ember.Handlebars.compile( filters_html ), - filterBinding: 'controller.namespace.entriesController.filterBy', - isAll: function() { - return Ember.empty( this.get('filter') ); - }.property( 'filter' ), - isActive: function() { - return this.get('filter') === 'active'; - }.property('filter'), - isCompleted: function() { - return this.get('filter') === 'completed'; - }.property('filter') - }); - } -); diff --git a/dependency-examples/emberjs_require/js/app/views/items.js b/dependency-examples/emberjs_require/js/app/views/items.js deleted file mode 100644 index 6a8a0d77a4..0000000000 --- a/dependency-examples/emberjs_require/js/app/views/items.js +++ /dev/null @@ -1,50 +0,0 @@ -define('app/views/items', [ - 'text!app/templates/items.html', - 'ember' - ], - /** - * View to render todos items - * - * @param String items_html, the html view for the `Todos` items - * @returns Class - */ - function( items_html ) { - return Ember.CollectionView.extend({ - contentBinding: 'controller.entries', - tagName: 'ul', - elementId: 'todo-list', - itemViewClass: Ember.View.extend({ - template: Ember.Handlebars.compile( items_html ), - classNames: [ 'view' ], - classNameBindings: ['content.completed', 'content.editing'], - doubleClick: function() { - this.get( 'content' ).set( 'editing', true ); - }, - removeItem: function() { - this.getPath( 'controller.content' ).removeObject( this.get( 'content' ) ); - }, - ItemEditorView: Ember.TextField.extend({ - valueBinding: 'content.title', - classNames: [ 'edit' ], - change: function() { - if ( Ember.empty( this.getPath( 'content.title' ) ) ) { - this.getPath( 'controller.content' ).removeObject( this.get( 'content' ) ); - } - }, - whenDone: function() { - this.get( 'content' ).set( 'editing', false ); - }, - focusOut: function() { - this.whenDone(); - }, - didInsertElement: function() { - this.$().focus(); - }, - insertNewline: function() { - this.whenDone(); - } - }) - }) - }) - } -); diff --git a/dependency-examples/emberjs_require/js/app/views/stats.js b/dependency-examples/emberjs_require/js/app/views/stats.js deleted file mode 100644 index 6ef2ac2afd..0000000000 --- a/dependency-examples/emberjs_require/js/app/views/stats.js +++ /dev/null @@ -1,22 +0,0 @@ -define('app/views/stats', [ - 'text!app/templates/stats.html', - 'ember' - ], - /** - * View to render todos stats - * - * @param String stats_html, stats indicator view - * @returns Class - */ - function( stats_html ) { - return Ember.View.extend({ - entriesBinding: 'controller.namespace.entriesController', - elementId: 'todo-count', - tagName: 'span', - template: Ember.Handlebars.compile( stats_html ), - oneLeft: function() { - return this.getPath( 'entries.remaining' ) === 1; - }.property( 'entries.remaining' ) - }) - } -); diff --git a/dependency-examples/emberjs_require/js/lib/ember-latest.min.js b/dependency-examples/emberjs_require/js/lib/ember-latest.min.js deleted file mode 100644 index 34b12191f1..0000000000 --- a/dependency-examples/emberjs_require/js/lib/ember-latest.min.js +++ /dev/null @@ -1,18 +0,0 @@ -// ========================================================================== -// Project: Ember - JavaScript Application Framework -// Copyright: ©2011-2012 Tilde Inc. and contributors -// Portions ©2006-2011 Strobe Inc. -// Portions ©2008-2011 Apple Inc. All rights reserved. -// License: Licensed under MIT license (see license.js) -// ========================================================================== - - -// Version: v0.9.8.1-484-g73ac0a4 -// Last commit: 73ac0a4 (2012-07-06 11:52:32 -0700) - - -(function(){"undefined"==typeof Ember&&(Ember={}),"undefined"!=typeof window&&(window.Em=window.Ember=Em=Ember),Ember.isNamespace=!0,Ember.toString=function(){return"Ember"},Ember.VERSION="1.0.pre",Ember.ENV="undefined"==typeof ENV?{}:ENV,Ember.config=Ember.config||{},Ember.EXTEND_PROTOTYPES=Ember.ENV.EXTEND_PROTOTYPES!==!1,Ember.SHIM_ES5=Ember.ENV.SHIM_ES5===!1?!1:Ember.EXTEND_PROTOTYPES,Ember.CP_DEFAULT_CACHEABLE=Ember.ENV.CP_DEFAULT_CACHEABLE!==!1,Ember.VIEW_PRESERVES_CONTEXT=Ember.ENV.VIEW_PRESERVES_CONTEXT!==!1,Ember.K=function(){return this},"undefined"==typeof Ember.assert&&(Ember.assert=Ember.K),"undefined"==typeof Ember.warn&&(Ember.warn=Ember.K),"undefined"==typeof Ember.deprecate&&(Ember.deprecate=Ember.K),"undefined"==typeof Ember.deprecateFunc&&(Ember.deprecateFunc=function(a,b){return b}),"undefined"==typeof ember_assert&&(window.ember_assert=Ember.K),"undefined"==typeof ember_warn&&(window.ember_warn=Ember.K),"undefined"==typeof ember_deprecate&&(window.ember_deprecate=Ember.K),"undefined"==typeof ember_deprecateFunc&&(window.ember_deprecateFunc=function(a,b){return b}),Ember.Logger=window.console||{log:Ember.K,warn:Ember.K,error:Ember.K}})(),function(){var a=function(a){return a&&Function.prototype.toString.call(a).indexOf("[native code]")>-1},b=a(Array.prototype.map)?Array.prototype.map:function(a){if(this===void 0||this===null)throw new TypeError;var b=Object(this),c=b.length>>>0;if(typeof a!="function")throw new TypeError;var d=new Array(c),e=arguments[1];for(var f=0;f>>0;if(typeof a!="function")throw new TypeError;var d=arguments[1];for(var e=0;e-1&&f.splice(g,1)},isEmpty:function(){return this.list.length===0},forEach:function(a,b){var c=this.list.slice();for(var d=0,e=c.length;d0?(e=b.slice(b.lastIndexOf(".")+1),b=b.slice(0,b.length-(e.length+1)),b!=="this"&&(a=Ember.getPath(a,b))):e=b;if(!e||e.length===0)throw new Error("You passed an empty path");if(!a){if(d)return;throw new Error("Object in path "+b+" could not be found or was destroyed.")}return Ember.set(a,e,c)},Ember.trySetPath=function(a,b,c){return Ember.setPath(a,b,c,!0)},Ember.isGlobalPath=function(a){return i.test(a)}}(),function(){function m(a,b,c){var d=c[b];return d===undefined&&a.unknownProperty&&(d=a.unknownProperty(b)),d}function n(a,b){return m(a,b,a)}function p(a,b){return m(a,b,d(a,!1).values||o)}function s(a,b,c){var e=d(a),f=e.values,g=c!==f[b];return g&&(Ember.propertyWillChange(a,b),r(a,b,c,e.values),Ember.propertyDidChange(a,b)),c}function t(a){return function(){return p(this,a)}}function u(a){return function(b){return s(this,a,b)}}function v(a,b){return b==="toString"?"function"!=typeof a.toString:!!a[b]}var a=Ember.USE_ACCESSORS,b=Ember.GUID_KEY,c=Ember.META_KEY,d=Ember.meta,e=Ember.platform.defineProperty,f,g,h=Ember.Descriptor=function(){},i=h.setup=function(a,b,c){e(a,b,{writable:!0,configurable:!0,enumerable:!0,value:c})},j=Ember.Descriptor.prototype;j.set=function(a,b,c){return a[b]=c,c},j.get=function(a,b){return n(a,b,a)},j.setup=i,j.teardown=function(a,b){return a[b]},j.val=function(a,b){return a[b]};var k=Ember.Descriptor.MUST_USE_SETTER=function(){this instanceof Ember.Object&&!this.isDestroyed},l={configurable:!0,enumerable:!0,set:k},o={},q=Ember.platform.hasPropertyAccessors,r;r=function(a,b,c,d){d[b]=c},q||(r=function(a,b,c,d){a[b]=c,d[b]=c}),g=new Ember.Descriptor,g.get=p,g.set=s,g.setup=function(a,b,c){e(a,b,{configurable:!0,enumerable:!0,set:k,get:t(b)}),d(a).values[b]=c},g.teardown=function(a,b){var c=d(a).values[b];return delete d(a).values[b],c},Ember.SIMPLE_PROPERTY=new Ember.Descriptor,f=Ember.SIMPLE_PROPERTY,f.unwatched=g.unwatched=f,f.watched=g.watched=g,Ember.defineProperty=function(a,b,c,g){var h=d(a,!1),i=h.descs,j=h.watching[b]>0,k=!0;return g===undefined?(k=!1,g=v(i,b)?i[b].teardown(a,b):a[b]):v(i,b)&&i[b].teardown(a,b),c||(c=f),c instanceof Ember.Descriptor?(h=d(a,!0),i=h.descs,c=(j?c.watched:c.unwatched)||c,i[b]=c,c.setup(a,b,g,j)):(i[b]&&(d(a).descs[b]=null),e(a,b,c)),k&&j&&Ember.overrideChains(a,b,h),this}}(),function(){function i(a,b){var d=c(a),e=d.deps,f;return e?e.__emberproto__!==a&&(e=d.deps=g(e),e.__emberproto__=a):e=d.deps={__emberproto__:a},f=e[b],f?f.__emberproto__!==a&&(f=e[b]=g(f),f.__emberproto__=a):f=e[b]={__emberproto__:a},f}function j(a,b,c){var d=i(a,c);d[b]=(d[b]||0)+1,Ember.watch(a,c)}function k(a,b,c){var d=i(a,c);d[b]=(d[b]||0)-1,Ember.unwatch(a,c)}function l(a,b,c){var d=a._dependentKeys,e=d?d.length:0;for(var f=0;f0,i=b._suspended,j;return b._suspended=this,h&&Ember.propertyWillChange(this,a),d&&delete g.cache[a],j=e.call(this,a,f),d&&(g.cache[a]=j),h&&Ember.propertyDidChange(this,a),b._suspended=i,j}}var a=Ember.get,b=Ember.getPath,c=Ember.meta,d=Ember.guidFor,e=Ember.USE_ACCESSORS,f=[].slice,g=Ember.create,h=Ember.platform.defineProperty;Ember.ComputedProperty=m,m.prototype=new Ember.Descriptor;var n={configurable:!0,enumerable:!0,get:function(){return undefined},set:Ember.Descriptor.MUST_USE_SETTER},q=m.prototype;q.cacheable=function(a){return this._cacheable=a!==!1,this},q.volatile=function(){return this.cacheable(!1)},q.property=function(){return this._dependentKeys=f.call(arguments),this},q.meta=function(a){return this._meta=a,this},q.setup=function(a,b,c){n.get=o(b,this),n.set=p(b,this),h(a,b,n),n.get=n.set=null,l(this,a,b)},q.teardown=function(a,b){var d=this._dependentKeys,e=d?d.length:0;for(var f=0;f0,h=this._suspended,i;return this._suspended=a,g&&Ember.propertyWillChange(a,b),e&&delete f.cache[b],i=this.func.call(a,b,d),e&&(f.cache[b]=i),g&&Ember.propertyDidChange(a,b),this._suspended=h,i},q.val=function(a,b){return c(a,!1).values[b]},Ember.platform.hasPropertyAccessors?e||(q.setup=function(a,b){h(a,b,n),l(this,a,b)}):q.setup=function(a,b,c){a[b]=undefined,l(this,a,b)},Ember.computed=function(a){var b;arguments.length>1&&(b=f.call(arguments,0,-1),a=f.call(arguments,-1)[0]);var c=new m(a);return b&&c.property.apply(c,b),c},Ember.cacheFor=function(a,b){var d=c(a,!1).cache;if(d&&b in d)return d[b]},Ember.computed.not=function(a){return Ember.computed(a,function(c){return!b(this,a)}).cacheable()},Ember.computed.empty=function(c){return Ember.computed(c,function(d){var e=b(this,c);return e===undefined||e===null||e===""||Ember.isArray(e)&&a(e,"length")===0}).cacheable()},Ember.computed.bool=function(a){return Ember.computed(a,function(c){return!!b(this,a)}).cacheable()}}(),function(){function j(a,b,c){d&&!c?h.push(a,b):Ember.sendEvent(a,b)}function k(){i.clear(),h.flush()}function l(b){return b+a}function m(a){return a+b}function n(a){return a.slice(0,-7)}function o(a){return a.slice(0,-7)}function p(a){return function(b,c,d){var e=d[0],f=n(d[1]),g,h=a.slice();c.length>2&&(g=Ember.getPath(Ember.isGlobalPath(f)?window:e,f)),h.unshift(e,f,g),c.apply(b,h)}}function r(a,b,c){var d=c[0],e=o(c[1]),f;b.length>2&&(f=Ember.getPath(d,e)),b.call(a,d,e,f)}var a=":change",b=":before",c=Ember.guidFor,d=0,e=[].slice,f=function(){this.targetSet={}};f.prototype.add=function(a,b){var c=this.targetSet,d=Ember.guidFor(a),e=c[d];return e||(c[d]=e={}),e[b]?!1:e[b]=!0},f.prototype.clear=function(){this.targetSet={}};var g=function(){this.targetSet={},this.queue=[]};g.prototype.push=function(a,b){var c=this.targetSet,d=this.queue,e=Ember.guidFor(a),f=c[e],g;f||(c[e]=f={}),g=f[b],g===undefined?f[b]=d.push(Ember.deferEvent(a,b))-1:d[g]=Ember.deferEvent(a,b)},g.prototype.flush=function(){var a=this.queue;this.queue=[],this.targetSet={};for(var b=0,c=a.length;b4){var g=e.call(arguments,4);f=p(g)}else f=q;return Ember.addListener(a,l(b),c,d,f),Ember.watch(a,b),this},Ember.observersFor=function(a,b){return Ember.listenersFor(a,l(b))},Ember.removeObserver=function(a,b,c,d){return Ember.unwatch(a,b),Ember.removeListener(a,l(b),c,d),this},Ember.addBeforeObserver=function(a,b,c,d){return Ember.addListener(a,m(b),c,d,r),Ember.watch(a,b),this},Ember._suspendBeforeObserver=function(a,b,c,d,e){return Ember._suspendListener(a,m(b),c,d,e)},Ember._suspendObserver=function(a,b,c,d,e){return Ember._suspendListener(a,l(b),c,d,e)},Ember.beforeObserversFor=function(a,b){return Ember.listenersFor(a,m(b))},Ember.removeBeforeObserver=function(a,b,c,d){return Ember.unwatch(a,b),Ember.removeListener(a,m(b),c,d),this},Ember.notifyObservers=function(a,b){if(a.isDestroying)return;j(a,l(b))},Ember.notifyBeforeObservers=function(a,b){if(a.isDestroying)return;var c,e,f=!1;if(d){if(!i.add(a,b))return;f=!0}j(a,m(b),f)}}(),function(){function m(a){return a.match(k)[0]}function n(a){return a==="*"||!l.test(a)}function p(b,c,d,e,f){var g=a(c);e[g]||(e[g]={});if(e[g][d])return;e[g][d]=!0;var h=f.deps;h=h&&h[d];if(h)for(var i in h){if(o[i])continue;b(c,i)}}function s(a,b,c){if(a.isDestroying)return;var d=q,e=!d;e&&(d=q={}),p(G,a,b,d,c),e&&(q=null)}function t(a,b,c){if(a.isDestroying)return;var d=r,e=!d;e&&(d=r={}),p(H,a,b,d,c),e&&(r=null)}function u(c,d,e){if(!c||"object"!=typeof c)return;var f=b(c),g=f.chainWatchers;if(!g||g.__emberproto__!==c)g=f.chainWatchers={__emberproto__:c};g[d]||(g[d]={}),g[d][a(e)]=e,Ember.watch(c,d)}function v(c,d,e){if(!c||"object"!=typeof c)return;var f=b(c,!1),g=f.chainWatchers;if(!g||g.__emberproto__!==c)return;g[d]&&delete g[d][a(e)],Ember.unwatch(c,d)}function x(){if(w.length===0)return;var a=w;w=[],j.call(a,function(a){a[0].add(a[1])})}function y(a){return b(a,!1).proto===a}function B(a){var c=b(a),d=c.chains;return d?d.value()!==a&&(d=c.chains=d.copy(a)):d=c.chains=new z(null,null,a),d}function C(a,b,c,d,e){var f=b.chainWatchers;if(!f||f.__emberproto__!==a)return;f=f[c];if(!f)return;for(var g in f){if(!f.hasOwnProperty(g))continue;f[g][d](e)}}function D(a,b,c){C(a,c,b,"willChange")}function E(a,b,c){C(a,c,b,"didChange")}function G(a,c,d){var e=b(a,!1),f=e.watching[c]>0||c==="length",g=e.proto,h=e.descs[c];if(!f)return;if(g===a)return;h&&h.willChange&&h.willChange(a,c),s(a,c,e),D(a,c,e),Ember.notifyBeforeObservers(a,c)}function H(a,c){var d=b(a,!1),e=d.watching[c]>0||c==="length",f=d.proto,g=d.descs[c];if(f===a)return;g&&g.didChange&&g.didChange(a,c);if(!e&&c!=="length")return;t(a,c,d),E(a,c,d),Ember.notifyObservers(a,c)}var a=Ember.guidFor,b=Ember.meta,c=Ember.get,d=Ember.set,e=Ember.normalizeTuple.primitive,f=Ember.SIMPLE_PROPERTY,g=Ember.GUID_KEY,h=Ember.META_KEY,i=Ember.notifyObservers,j=Ember.ArrayPolyfills.forEach,k=/^([^\.\*]+)/,l=/[\.\*]/,o={__emberproto__:!0},q,r,w=[],z=function(a,b,c,d){var e;this._parent=a,this._key=b,this._watching=c===undefined,this._value=c,this._separator=d||".",this._paths={},this._watching&&(this._object=a.value(),this._object&&u(this._object,this._key,this)),this._parent&&this._parent._key==="@each"&&this.value()},A=z.prototype;A.value=function(){if(this._value===undefined&&this._watching){var a=this._parent.value();this._value=a&&!y(a)?c(a,this._key):undefined}return this._value},A.destroy=function(){if(this._watching){var a=this._object;a&&v(a,this._key,this),this._watching=!1}},A.copy=function(a){var b=new z(null,null,a,this._separator),c=this._paths,d;for(d in c){if(c[d]<=0)continue;b.add(d)}return b},A.add=function(a){var b,c,d,f,g,h;h=this._paths,h[a]=(h[a]||0)+1,b=this.value(),c=e(b,a);if(c[0]&&c[0]===b)a=c[1],d=m(a),a=a.slice(d.length+1);else{if(!c[0]){w.push([this,a]),c.length=0;return}f=c[0],d=a.slice(0,0-(c[1].length+1)),g=a.slice(d.length,d.length+1),a=c[1]}c.length=0,this.chain(d,a,f,g)},A.remove=function(a){var b,c,d,f,g;g=this._paths,g[a]>0&&g[a]--,b=this.value(),c=e(b,a),c[0]===b?(a=c[1],d=m(a),a=a.slice(d.length+1)):(f=c[0],d=a.slice(0,0-(c[1].length+1)),a=c[1]),c.length=0,this.unchain(d,a)},A.count=0,A.chain=function(a,b,c,d){var e=this._chains,f;e||(e=this._chains={}),f=e[a],f||(f=e[a]=new z(this,a,c,d)),f.count++,b&&b.length>0&&(a=m(b),b=b.slice(a.length+1),f.chain(a,b))},A.unchain=function(a,b){var c=this._chains,d=c[a];b&&b.length>1&&(a=m(b),b=b.slice(a.length+1),d.unchain(a,b)),d.count--,d.count<=0&&(delete c[d._key],d.destroy())},A.willChange=function(){var a=this._chains;if(a)for(var b in a){if(!a.hasOwnProperty(b))continue;a[b].willChange()}this._parent&&this._parent.chainWillChange(this,this._key,1)},A.chainWillChange=function(a,b,c){this._key&&(b=this._key+this._separator+b),this._parent?this._parent.chainWillChange(this,b,c+1):(c>1&&Ember.propertyWillChange(this.value(),b),b="this."+b,this._paths[b]>0&&Ember.propertyWillChange(this.value(),b))},A.chainDidChange=function(a,b,c){this._key&&(b=this._key+this._separator+b),this._parent?this._parent.chainDidChange(this,b,c+1):(c>1&&Ember.propertyDidChange(this.value(),b),b="this."+b,this._paths[b]>0&&Ember.propertyDidChange(this.value(),b))},A.didChange=function(a){if(this._watching){var b=this._parent.value();b!==this._object&&(v(this._object,this._key,this),this._object=b,u(b,this._key,this)),this._value=undefined,this._parent&&this._parent._key==="@each"&&this.value()}var c=this._chains;if(c)for(var d in c){if(!c.hasOwnProperty(d))continue;c[d].didChange(a)}if(a)return;this._parent&&this._parent.chainDidChange(this,this._key,1)},Ember.overrideChains=function(a,b,c){C(a,c,b,"didChange",!0)};var F=Ember.SIMPLE_PROPERTY.watched;Ember.watch=function(a,c){if(c==="length"&&Ember.typeOf(a)==="array")return this;var d=b(a),e=d.watching,f;return e[c]?e[c]=(e[c]||0)+1:(e[c]=1,n(c)?("function"==typeof a.willWatchProperty&&a.willWatchProperty(c),f=d.descs[c],f=f?f.watched:F,f&&Ember.defineProperty(a,c,f)):B(a).add(c)),this},Ember.isWatching=function(a,c){return!!b(a).watching[c]},Ember.watch.flushPending=x,Ember.unwatch=function(a,c){if(c==="length"&&Ember.typeOf(a)==="array")return this;var d=b(a).watching,e,g;return d[c]===1?(d[c]=0,n(c)?(e=b(a).descs[c],e=e?e.unwatched:f,e&&Ember.defineProperty(a,c,e),"function"==typeof a.didUnwatchProperty&&a.didUnwatchProperty(c)):B(a).remove(c)):d[c]>1&&d[c]--,this},Ember.rewatch=function(a){var c=b(a,!1),d=c.chains,e=c.bindings,f,h;return g in a&&!a.hasOwnProperty(g)&&Ember.generateGuid(a,"ember"),d&&d.value()!==a&&B(a),this},Ember.propertyWillChange=G,Ember.propertyDidChange=H;var I=[];Ember.destroy=function(a){var b=a[h],c,d,e,f;if(b){a[h]=null,c=b.chains;if(c){I.push(c);while(I.length>0){c=I.pop(),d=c._chains;if(d)for(e in d)d.hasOwnProperty(e)&&I.push(d[e]);c._watching&&(f=c._object,f&&v(f,c._key,c))}}}}}(),function(){function f(a,b,e,f){return c(a,["listeners",b,d(e)],f)}function g(a,c){var d=b(a,!1).listeners;return d?d[c]||!1:!1}function i(a,b,c){if(!a)return!1;for(var d in a){if(h[d])continue;var e=a[d];if(e)for(var f in e){if(h[f])continue;var g=e[f];if(g&&b(g,c)===!0)return!0}}return!1}function j(a,b){var c=a.method,d=a.target,e=a.xform;d||(d=b[0]),"string"==typeof c&&(c=d[c]),e?e(d,c,b):c.apply(d,b)}function k(a,b,c,e,g){!e&&"function"==typeof c&&(e=c,c=null);var h=f(a,b,c,!0),i=d(e);h[i]?h[i].xform=g:h[i]={target:c,method:e,xform:g},"function"==typeof a.didAddListener&&a.didAddListener(b,c,e)}function l(a,b,c,e){!e&&"function"==typeof c&&(e=c,c=null);var g=f(a,b,c,!0),h=d(e);g&&g[h]&&(g[h]=null),a&&"function"==typeof a.didRemoveListener&&a.didRemoveListener(b,c,e)}function m(a,b,c,e,g){!e&&"function"==typeof c&&(e=c,c=null);var h=f(a,b,c,!0),i=d(e),j=h&&h[i];h[i]=null;try{return g.call(c)}finally{h[i]=j}}function n(a){var c=b(a,!1).listeners,d=[];if(c)for(var e in c)!h[e]&&c[e]&&d.push(e);return d}function o(a,b){return a!==Ember&&"function"==typeof a.sendEvent&&a.sendEvent.apply(a,e.call(arguments,1)),i(g(a,b),j,arguments),!0}function p(a,b){var c=g(a,b),d=[],f=arguments;return i(c,function(a){d.push(a)}),function(){if(a.isDestroyed)return;a!==Ember&&"function"==typeof a.sendEvent&&a.sendEvent.apply(a,e.call(f,1));for(var b=0,c=d.length;b0&&(d=d.length>e?a.call(d,e):null);if("function"!=typeof Ember.onerror)return c.apply(b||this,d||[]);try{return c.apply(b||this,d||[])}catch(f){Ember.onerror(f)}}function h(){g=null,f.currentRunLoop&&f.end()}function k(){j=null;var a=+(new Date),b=-1;for(var d in i){if(!i.hasOwnProperty(d))continue;var e=i[d];if(e&&e.expires)if(a>=e.expires)delete i[d],c(e.target,e.method,e.args,2);else if(b<0||e.expires0&&(j=setTimeout(k,b- +(new Date)))}function l(a,b){b[this.tguid]&&delete b[this.tguid][this.mguid],i[a]&&c(this.target,this.method,this.args,2),delete i[a]}function n(){m=null;for(var a in i){if(!i.hasOwnProperty(a))continue;var b=i[a];b.next&&(delete i[a],c(b.target,b.method,b.args,2))}}var a=[].slice,b=Ember.ArrayPolyfills.forEach,d,e=function(a){this._prev=a||null,this.onceTimers={}};e.prototype={end:function(){this.flush()},prev:function(){return this._prev},schedule:function(b,c,d){var e=this._queues,f;e||(e=this._queues={}),f=e[b],f||(f=e[b]=[]);var g=arguments.length>3?a.call(arguments,3):null;return f.push({target:c,method:d,args:g}),this},flush:function(a){function j(a){c(a.target,a.method,a.args)}var e,f,g,h,i;if(!this._queues)return this;Ember.watch.flushPending();if(a)while(this._queues&&(h=this._queues[a])){this._queues[a]=null;if(a==="sync"){i=Ember.LOG_BINDINGS,i&&Ember.Logger.log("Begin: Flush Sync Queue"),Ember.beginPropertyChanges();try{b.call(h,j)}finally{Ember.endPropertyChanges()}i&&Ember.Logger.log("End: Flush Sync Queue")}else b.call(h,j)}else{e=Ember.run.queues,g=e.length,f=0;a:while(f("+this._from+" -> "+this._to+")"+a},connect:function(a){var b=!this._oneWay;return Ember.addObserver(a,this._from,this,this.fromDidChange),b&&Ember.addObserver(a,this._to,this,this.toDidChange),Ember.meta(a,!1).proto!==a&&this._scheduleSync(a,"fwd"),this._readyToSync=!0,this},disconnect:function(a){var b=!this._oneWay;return Ember.removeObserver(a,this._from,this,this.fromDidChange),b&&Ember.removeObserver(a,this._to,this,this.toDidChange),this._readyToSync=!1,this},fromDidChange:function(a){this._scheduleSync(a,"fwd")},toDidChange:function(a){this._scheduleSync(a,"back")},_scheduleSync:function(a,b){var c=this._directionMap,d=c.get(a);d||(Ember.run.schedule("sync",this,this._sync,a),c.set(a,b)),d==="back"&&b==="fwd"&&c.set(a,"fwd")},_sync:function(a){var c=Ember.LOG_BINDINGS;if(a.isDestroyed||!this._readyToSync)return;var d=this._directionMap,e=d.get(a),g=this._from,h=this._to;d.remove(a);if(e==="fwd"){var i=f(a,this._from);c&&Ember.Logger.log(" ",this.toString(),"->",i,a),this._oneWay?Ember.trySetPath(Ember.isGlobalPath(h)?window:a,h,i):Ember._suspendObserver(a,h,this,this.toDidChange,function(){Ember.trySetPath(Ember.isGlobalPath(h)?window:a,h,i)})}else if(e==="back"){var j=b(a,this._to);c&&Ember.Logger.log(" ",this.toString(),"<-",j,a),Ember._suspendObserver(a,g,this,this.fromDidChange,function(){Ember.trySetPath(Ember.isGlobalPath(g)?window:a,g,j)})}}},h(g,{from:function(){var a=this,b=new a;return b.from.apply(b,arguments)},to:function(){var a=this,b=new a;return b.to.apply(b,arguments)},oneWay:function(a,b){var c=this,d=new c(null,a);return d.oneWay(b)}}),Ember.Binding=g,Ember.bind=function(a,b,c){return(new Ember.Binding(b,c)).connect(a)},Ember.oneWay=function(a,b,c){return(new Ember.Binding(b,c)).oneWay().connect(a)}}(),function(){function n(a,b){var c=Ember.meta(a,b!==!1),d=c.mixins;return b===!1?d||j:(d?d.__emberproto__!==a&&(d=c.mixins=l(d),d.__emberproto__=a):d=c.mixins={__emberproto__:a},d)}function o(b,c){return c&&c.length>0&&(b.mixins=f.call(c,function(b){if(b instanceof a)return b;var c=new a;return c.properties=b,c})),b}function q(a){return"function"!=typeof a||a.isMethod===!1?!1:g.call(p,a)<0}function r(c,d,e,f,i){function v(a){delete e[a],delete f[a]}var j=c.length,k,l,n,o,p,s,t,u;for(k=0;k=0||s==="concatenatedProperties"){var y=f[s]||i[s];p=y?y.concat(p):Ember.makeArray(p)}e[s]=Ember.SIMPLE_PROPERTY,f[s]=p}}o.hasOwnProperty("toString")&&(i.toString=o.toString)}else l.mixins&&(r(l.mixins,d,e,f,i),l._without&&h.call(l._without,v))}}function s(a){var b=Ember.meta(a),c=b.required;if(!c||c.__emberproto__!==a)c=b.required=c?l(c):{__ember_count__:0},c.__emberproto__=a;return c}function t(a){return"function"==typeof a&&a.__ember_observes__}function u(a){return"function"==typeof a&&a.__ember_observesBefore__}function w(a,b,c){if(v.test(b)){var d=c.bindings;d?d.__emberproto__!==a&&(d=c.bindings=l(c.bindings),d.__emberproto__=a):d=c.bindings={__emberproto__:a},d[b]=!0}}function x(a,b){var c=(b||Ember.meta(a)).bindings,d,e;if(c)for(d in c)e=d!=="__emberproto__"&&a[d],e&&(e instanceof Ember.Binding?(e=e.copy(),e.to(d.slice(0,-7))):e=new Ember.Binding(d.slice(0,-7),e),e.connect(a),a[d]=e)}function y(a,d,e){var f= -{},g={},h=Ember.meta(a),i=h.required,j,l,m,o,p;r(d,n(a),f,g,a),Ember.MixinDelegate.detect(a)&&(l=g.willApplyProperty||a.willApplyProperty,m=g.didApplyProperty||a.didApplyProperty);for(j in f){if(!f.hasOwnProperty(j))continue;p=f[j],o=g[j];if(p===b)j in a||(i=s(a),i.__ember_count__++,i[j]=!0);else{while(p instanceof c){var q=p.methodName;f[q]?(o=g[q],p=f[q]):h.descs[q]?(p=h.descs[q],o=p.val(a,q)):(o=a[q],p=Ember.SIMPLE_PROPERTY)}l&&l.call(a,j);var v=t(o),y=v&&t(a[j]),z=u(o),A=z&&u(a[j]),B,C;if(y){B=y.length;for(C=0;C0){var D=[];for(j in i){if(k[j])continue;D.push(j)}}return a}function B(a,b,c){var d=m(a);if(c[d])return!1;c[d]=!0;if(a===b)return!0;var e=a.mixins,f=e?e.length:0;while(--f>=0)if(B(e[f],b,c))return!0;return!1}function C(a,b,c){if(c[m(b)])return;c[m(b)]=!0;if(b.properties){var d=b.properties;for(var e in d)d.hasOwnProperty(e)&&(a[e]=!0)}else b.mixins&&h.call(b.mixins,function(b){C(a,b,c)})}function F(a,b,c){var e=a.length;for(var f in b){if(!b.hasOwnProperty||!b.hasOwnProperty(f))continue;var g=b[f];a[e]=f;if(g&&g.toString===d)g[D]=a.join(".");else if(g&&E(g,"isNamespace")){if(c[m(g)])continue;c[m(g)]=!0,F(a,g,c)}}a.length=e}function G(){var a=Ember.Namespace,b,c;if(a.PROCESSED)return;for(var d in window){if(d==="globalStorage"&&window.StorageList&&window.globalStorage instanceof window.StorageList)continue;if(window.hasOwnProperty&&!window.hasOwnProperty(d))continue;try{b=window[d],c=b&&E(b,"isNamespace")}catch(e){continue}c&&(b[D]=d)}}var a,b,c,d,e,f=Ember.ArrayPolyfills.map,g=Ember.ArrayPolyfills.indexOf,h=Ember.ArrayPolyfills.forEach,i=[].slice,j={},k={__emberproto__:!0,__ember_count__:!0},l=Ember.create,m=Ember.guidFor,p=[Boolean,Object,Number,Array,Date,String],v=Ember.IS_BINDING=/^.+Binding$/;Ember.mixin=function(a){var b=i.call(arguments,1);return y(a,b,!1)},Ember.Mixin=function(){return o(this,arguments)},a=Ember.Mixin,a._apply=y,a.applyPartial=function(a){var b=i.call(arguments,1);return y(a,b,!0)},a.finishPartial=function(a){return x(a),a},a.create=function(){d.processed=!1;var a=this;return o(new a,arguments)};var z=a.prototype;z.reopen=function(){var b,c;this.properties?(b=a.create(),b.properties=this.properties,delete this.properties,this.mixins=[b]):this.mixins||(this.mixins=[]);var d=arguments.length,e=this.mixins,f;for(f=0;f=0)return f[h];if(Ember.typeOf(b)==="array"){g=b.slice();if(c){h=g.length;while(--h>=0)g[h]=e(g[h],c,d,f)}}else if(Ember.Copyable&&Ember.Copyable.detect(b))g=b.copy(c,d,f);else{g={};for(i in b){if(!b.hasOwnProperty(i))continue;g[i]=c?e(b[i],c,d,f):b[i]}}return c&&(d.push(b),f.push(g)),g}var a=Ember.EnumerableUtils.indexOf,b={},c="Boolean Number String Function Array Date RegExp Object".split(" ");Ember.ArrayPolyfills.forEach.call(c,function(a){b["[object "+a+"]"]=a.toLowerCase()});var d=Object.prototype.toString;Ember.typeOf=function(a){var c;return c=a===null||a===undefined?String(a):b[d.call(a)]||"object",c==="function"?Ember.Object&&Ember.Object.detect(a)&&(c="class"):c==="object"&&(a instanceof Error?c="error":Ember.Object&&a instanceof Ember.Object?c="instance":c="object"),c},Ember.none=function(a){return a===null||a===undefined},Ember.empty=function(a){return a===null||a===undefined||a.length===0&&typeof a!="function"},Ember.compare=function f(a,b){if(a===b)return 0;var c=Ember.typeOf(a),d=Ember.typeOf(b),e=Ember.Comparable;if(e){if(c==="instance"&&e.detect(a.constructor))return a.constructor.compare(a,b);if(d==="instance"&&e.detect(b.constructor))return 1-b.constructor.compare(b,a)}var g=Ember.ORDER_DEFINITION_MAPPING;if(!g){var h=Ember.ORDER_DEFINITION;g=Ember.ORDER_DEFINITION_MAPPING={};var i,j;for(i=0,j=h.length;il)return 1;switch(c){case"boolean":case"number":if(ab)return 1;return 0;case"string":var m=a.localeCompare(b);if(m<0)return-1;if(m>0)return 1;return 0;case"array":var n=a.length,o=b.length,p=Math.min(n,o),q=0,r=0;while(q===0&&ro)return 1;return 0;case"instance":if(Ember.Comparable&&Ember.Comparable.detect(a))return a.compare(a,b);return 0;default:return 0}},Ember.copy=function(a,b){return"object"!=typeof a||a===null?a:Ember.Copyable&&Ember.Copyable.detect(a)?a.copy(b):e(a,b,b?[]:null,b?[]:null)},Ember.inspect=function(a){var b,c=[];for(var d in a)if(a.hasOwnProperty(d)){b=a[d];if(b==="toString")continue;Ember.typeOf(b)==="function"&&(b="function() { ... }"),c.push(d+": "+b)}return"{"+c.join(" , ")+"}"},Ember.isEqual=function(a,b){return a&&"function"==typeof a.isEqual?a.isEqual(b):a===b},Ember.ORDER_DEFINITION=Ember.ENV.ORDER_DEFINITION||["undefined","null","boolean","number","string","array","object","instance","function","class"],Ember.keys=Object.keys,Ember.keys||(Ember.keys=function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b}),Ember.Error=function(){var a=Error.prototype.constructor.apply(this,arguments);for(var b in a)a.hasOwnProperty(b)&&(this[b]=a[b]);this.message=a.message},Ember.Error.prototype=Ember.create(Error.prototype)}(),function(){var a=/[ _]/g,b={},c=/([a-z])([A-Z])/g,d=/(\-|_|\s)+(.)?/g,e=/([a-z\d])([A-Z]+)/g,f=/\-|\s+/g;Ember.STRINGS={},Ember.String={fmt:function(a,b){var c=0;return a.replace(/%@([0-9]+)?/g,function(a,d){return d=d?parseInt(d,0)-1:c++,a=b[d],(a===null?"(null)":a===undefined?"":a).toString()})},loc:function(a,b){return a=Ember.STRINGS[a]||a,Ember.String.fmt(a,b)},w:function(a){return a.split(/\s+/)},decamelize:function(a){return a.replace(c,"$1_$2").toLowerCase()},dasherize:function(c){var d=b,e=d[c];return e?e:(e=Ember.String.decamelize(c).replace(a,"-"),d[c]=e,e)},camelize:function(a){return a.replace(d,function(a,b,c){return c?c.toUpperCase():""})},classify:function(a){var b=Ember.String.camelize(a);return b.charAt(0).toUpperCase()+b.substr(1)},underscore:function(a){return a.replace(e,"$1_$2").replace(f,"_").toLowerCase()}}}(),function(){var a=Ember.String.fmt,b=Ember.String.w,c=Ember.String.loc,d=Ember.String.camelize,e=Ember.String.decamelize,f=Ember.String.dasherize,g=Ember.String.underscore;Ember.EXTEND_PROTOTYPES&&(String.prototype.fmt=function(){return a(this,arguments)},String.prototype.w=function(){return b(this)},String.prototype.loc=function(){return c(this,arguments)},String.prototype.camelize=function(){return d(this)},String.prototype.decamelize=function(){return e(this)},String.prototype.dasherize=function(){return f(this)},String.prototype.underscore=function(){return g(this)})}(),function(){var a=Array.prototype.slice;Ember.EXTEND_PROTOTYPES&&(Function.prototype.property=function(){var a=Ember.computed(this);return a.property.apply(a,arguments)},Function.prototype.observes=function(){return this.__ember_observes__=a.call(arguments),this},Function.prototype.observesBefore=function(){return this.__ember_observesBefore__=a.call(arguments),this})}(),function(){}(),function(){function f(){return e.length===0?{}:e.pop()}function g(a){return e.push(a),null}function h(b,c){function e(e){var f=a(e,b);return d?c===f:!!f}var d=arguments.length===2;return e}function i(a,b,c){b.call(a,c[0],c[2],c[3])}var a=Ember.get,b=Ember.set,c=Array.prototype.slice,d=Ember.EnumerableUtils.indexOf,e=[];Ember.Enumerable=Ember.Mixin.create({isEnumerable:!0,nextObject:Ember.required(Function),firstObject:Ember.computed(function(){if(a(this,"length")===0)return undefined;var b=f(),c;return c=this.nextObject(0,null,b),g(b),c}).property("[]").cacheable(),lastObject:Ember.computed(function(){var b=a(this,"length");if(b===0)return undefined;var c=f(),d=0,e,h=null;do h=e,e=this.nextObject(d++,h,c);while(e!==undefined);return g(c),h}).property("[]").cacheable(),contains:function(a){return this.find(function(b){return b===a})!==undefined},forEach:function(b,c){if(typeof b!="function")throw new TypeError;var d=a(this,"length"),e=null,h=f();c===undefined&&(c=null);for(var i=0;i1&&(b=c.call(arguments,1)),this.forEach(function(c,e){var f=c&&c[a];"function"==typeof f&&(d[e]=b?f.apply(c,b):f.call(c))},this),d},toArray:function(){var a=[];return this.forEach(function(b,c){a[c]=b}),a},compact:function(){return this.without(null)},without:function(a){if(!this.contains(a))return this;var b=[];return this.forEach(function(c){c!==a&&(b[b.length]=c)}),b},uniq:function(){var a=[];return this.forEach(function(b){d(a,b)<0&&a.push(b)}),a},"[]":Ember.computed(function(a,b){return this}).property().cacheable(),addEnumerableObserver:function(b,c){var d=c&&c.willChange||"enumerableWillChange",e=c&&c.didChange||"enumerableDidChange",f=a(this,"hasEnumerableObservers");return f||Ember.propertyWillChange(this,"hasEnumerableObservers"),Ember.addListener(this,"@enumerable:before",b,d,i),Ember.addListener(this,"@enumerable:change",b,e,i),f||Ember.propertyDidChange(this,"hasEnumerableObservers"),this},removeEnumerableObserver:function(b,c){var d=c&&c.willChange||"enumerableWillChange",e=c&&c.didChange||"enumerableDidChange",f=a(this,"hasEnumerableObservers");return f&&Ember.propertyWillChange(this,"hasEnumerableObservers"),Ember.removeListener(this,"@enumerable:before",b,d),Ember.removeListener(this,"@enumerable:change",b,e),f&&Ember.propertyDidChange(this,"hasEnumerableObservers"),this},hasEnumerableObservers:Ember.computed(function(){return Ember.hasListeners(this,"@enumerable:change")||Ember.hasListeners(this,"@enumerable:before")}).property().cacheable(),enumerableContentWillChange:function(b,c){var d,e,f;return"number"==typeof b?d=b:b?d=a(b,"length"):d=b=-1,"number"==typeof c?e=c:c?e=a(c,"length"):e=c=-1,f=e<0||d<0||e-d!==0,b===-1&&(b=null),c===-1&&(c=null),Ember.propertyWillChange(this,"[]"),f&&Ember.propertyWillChange(this,"length"),Ember.sendEvent(this,"@enumerable:before",b,c),this},enumerableContentDidChange:function(b,c){var d=this.propertyDidChange,e,f,g;return"number"==typeof b?e=b:b?e=a(b,"length"):e=b=-1,"number"==typeof c?f=c:c?f=a(c,"length"):f=c=-1,g=f<0||e<0||f-e!==0,b===-1&&(b=null),c===-1&&(c=null),Ember.sendEvent(this,"@enumerable:change",b,c),g&&Ember.propertyDidChange(this,"length"),Ember.propertyDidChange(this,"[]"),this}})}(),function(){function f(a){return a===null||a===undefined}function g(a,b,c){b.call(a,c[0],c[2],c[3],c[4])}var a=Ember.get,b=Ember.set,c=Ember.meta,d=Ember.EnumerableUtils.map,e=Ember.cacheFor;Ember.Array=Ember.Mixin.create(Ember.Enumerable,{isSCArray:!0,length:Ember.required(),objectAt:function(b){return b<0||b>=a(this,"length")?undefined:a(this,b)},objectsAt:function(a){var b=this;return d(a,function(a){return b.objectAt(a)})},nextObject:function(a){return this.objectAt(a)},"[]":Ember.computed(function(b,c){return c!==undefined&&this.replace(0,a(this,"length"),c),this}).property().cacheable(),firstObject:Ember.computed(function(){return this.objectAt(0)}).property().cacheable(),lastObject:Ember.computed(function(){return this.objectAt(a(this,"length")-1)}).property().cacheable(),contains:function(a){return this.indexOf(a)>=0},slice:function(b,c){var d=[],e=a(this,"length");f(b)&&(b=0);if(f(c)||c>e)c=e;while(b=e)c=e-1;c<0&&(c+=e);for(d=c;d>=0;d--)if(this.objectAt(d)===b)return d;return-1},addArrayObserver:function(b,c){var d=c&&c.willChange||"arrayWillChange",e=c&&c.didChange||"arrayDidChange",f=a(this,"hasArrayObservers");return f||Ember.propertyWillChange(this,"hasArrayObservers"),Ember.addListener(this,"@array:before",b,d,g),Ember.addListener(this,"@array:change",b,e,g),f||Ember.propertyDidChange(this,"hasArrayObservers"),this},removeArrayObserver:function(b,c){var d=c&&c.willChange||"arrayWillChange",e=c&&c.didChange||"arrayDidChange",f=a(this,"hasArrayObservers");return f&&Ember.propertyWillChange(this,"hasArrayObservers"),Ember.removeListener(this,"@array:before",b,d,g),Ember.removeListener(this,"@array:change",b,e,g),f&&Ember.propertyDidChange(this,"hasArrayObservers"),this},hasArrayObservers:Ember.computed(function(){return Ember.hasListeners(this,"@array:change")||Ember.hasListeners(this,"@array:before")}).property().cacheable(),arrayContentWillChange:function(b,c,d){b===undefined?(b=0,c=d=-1):(c===undefined&&(c=-1),d===undefined&&(d=-1)),Ember.isWatching(this,"@each")&&a(this,"@each"),Ember.sendEvent(this,"@array:before",b,c,d);var e,f;if(b>=0&&c>=0&&a(this,"hasEnumerableObservers")){e=[],f=b+c;for(var g=b;g=0&&d>=0&&a(this,"hasEnumerableObservers")){f=[],g=b+d;for(var h=b;hc(this,"length"))throw new Error(a);return this.replace(b,0,[d]),this},removeAt:function(d,e){var f=0;if("number"==typeof d){if(d<0||d>=c(this,"length"))throw new Error(a);e===undefined&&(e=1),this.replace(d,e,b)}return this},pushObject:function(a){return this.insertAt(c(this,"length"),a),a},pushObjects:function(a){return this.replace(c(this,"length"),0,a),this},popObject:function(){var a=c(this,"length");if(a===0)return null;var b=this.objectAt(a-1);return this.removeAt(a-1,1),b},shiftObject:function(){if(c(this,"length")===0)return null;var a=this.objectAt(0);return this.removeAt(0),a},unshiftObject:function(a){return this.insertAt(0,a),a},unshiftObjects:function(a){return this.replace(0,0,a),this},removeObject:function(a){var b=c(this,"length")||0;while(--b>=0){var d=this.objectAt(b);d===a&&this.removeAt(b)}return this},addObject:function(a){return this.contains(a)||this.pushObject(a),this}})}(),function(){var a=Ember.get,b=Ember.set;Ember.Observable=Ember.Mixin.create({isObserverable:!0,get:function(b){return a(this,b)},getProperties:function(){var b={},c=arguments;arguments.length===1&&Ember.typeOf(arguments[0])==="array"&&(c=arguments[0]);for(var d=0;d"}}),Ember.config.overridePrototypeMixin&&Ember.config.overridePrototypeMixin(k.PrototypeMixin),k.__super__=null;var l=Ember.Mixin.create({ClassMixin:Ember.required(),PrototypeMixin:Ember.required(),isClass:!0,isMethod:!1,extend:function(){var a=j(),b;a.ClassMixin=Ember.Mixin.create(this.ClassMixin),a.PrototypeMixin=Ember.Mixin.create(this.PrototypeMixin),a.ClassMixin.ownerConstructor=a,a.PrototypeMixin.ownerConstructor=a;var c=a.PrototypeMixin;return c.reopen.apply(c,arguments),a.superclass=this,a.__super__=this.prototype,b=a.prototype=e(this.prototype),b.constructor=a,Ember.generateGuid(b,"ember"),h(b).proto=b,a.ClassMixin.apply(a),a},create:function(){var a=this;return arguments.length>0&&this._initMixins(arguments),new a},reopen:function(){this.willReopen();var a=this.PrototypeMixin;return a.reopen.apply(a,arguments),this},reopenClass:function(){var a=this.ClassMixin;return a.reopen.apply(a,arguments),Ember.Mixin._apply(this,arguments,!1),this},detect:function(a){if("function"!=typeof a)return!1;while(a){if(a===this)return!0;a=a.superclass}return!1},detectInstance:function(a){return a instanceof this},metaForProperty:function(a){var b=h(this.proto(),!1).descs[a];return b._meta||{}},eachComputedProperty:function(a,b){var c=this.proto(),d=h(c).descs,e={},f;for(var g in d)f=d[g],f instanceof Ember.ComputedProperty&&a.call(b||this,g,f._meta||e)}});Ember.config.overrideClassMixin&&Ember.config.overrideClassMixin(l),k.ClassMixin=l,l.apply(k),Ember.CoreObject=k}(),function(){var a=Ember.get,b=Ember.set,c=Ember.guidFor,d=Ember.none;Ember.Set=Ember.CoreObject.extend(Ember.MutableEnumerable,Ember.Copyable,Ember.Freezable,{length:0,clear:function(){if(this.isFrozen)throw new Error(Ember.FROZEN_ERROR);var d=a(this,"length");if(d===0)return this;var e;this.enumerableContentWillChange(d,0),Ember.propertyWillChange(this,"firstObject"),Ember.propertyWillChange(this,"lastObject");for(var f=0;f=0)if(!b.contains(this[c]))return!1;return!0},add:Ember.alias("addObject"),remove:Ember.alias("removeObject"),pop:function(){if(a(this,"isFrozen"))throw new Error(Ember.FROZEN_ERROR);var b=this.length>0?this[this.length-1]:null;return this.remove(b),b},push:Ember.alias("addObject"),shift:Ember.alias("pop"),unshift:Ember.alias("push"),addEach:Ember.alias("addObjects"),removeEach:Ember.alias("removeObjects"),init:function(a){this._super(),a&&this.addObjects(a)},nextObject:function(a){return this[a]},firstObject:Ember.computed(function(){return this.length>0?this[0]:undefined}).property().cacheable(),lastObject:Ember.computed(function(){return this.length>0?this[this.length-1]:undefined}).property().cacheable(),addObject:function(e){if(a(this,"isFrozen"))throw new Error(Ember.FROZEN_ERROR);if(d(e))return this;var f=c(e),g=this[f],h=a(this,"length"),i;return g>=0&&g=0&&g=0},copy:function(){var d=this.constructor,e=new d,f=a(this,"length");b(e,"length",f);while(--f>=0)e[f]=this[f],e[c(this[f])]=f;return e},toString:function(){var a=this.length,b,c=[];for(b=0;b".fmt(c.join(","))}})}(),function(){Ember.Object=Ember.CoreObject.extend(Ember.Observable)}(),function(){var a=Ember.ArrayPolyfills.indexOf;Ember.Namespace=Ember.Object.extend({isNamespace:!0,init:function(){Ember.Namespace.NAMESPACES.push(this),Ember.Namespace.PROCESSED=!1},toString:function(){return Ember.identifyNamespaces(),this[Ember.GUID_KEY+"_name"]},destroy:function(){var b=Ember.Namespace.NAMESPACES;window[this.toString()]=undefined,b.splice(a.call(b,this),1),this._super()}}),Ember.Namespace.NAMESPACES=[Ember],Ember.Namespace.PROCESSED=!1}(),function(){Ember.Application=Ember.Namespace.extend()}(),function(){var a=Ember.get,b=Ember.set;Ember.ArrayProxy=Ember.Object.extend(Ember.MutableArray,{content:null,arrangedContent:Ember.computed("content",function(){return a(this,"content")}).cacheable(),objectAtContent:function(b){return a(this,"arrangedContent").objectAt(b)},replaceContent:function(b,c,d){a(this,"arrangedContent").replace(b,c,d)},_contentWillChange:Ember.beforeObserver(function(){var b=a(this,"content");b&&b.removeArrayObserver(this,{willChange:"contentArrayWillChange",didChange:"contentArrayDidChange"})},"content"),contentArrayWillChange:Ember.K,contentArrayDidChange:Ember.K,_contentDidChange:Ember.observer(function(){var b=a(this,"content"),c=b?a(b,"length"):0;b&&b.addArrayObserver(this,{willChange:"contentArrayWillChange",didChange:"contentArrayDidChange"})},"content"),_arrangedContentWillChange:Ember.beforeObserver(function(){var b=a(this,"arrangedContent"),c=b?a(b,"length"):0;this.arrangedContentArrayWillChange(this,0,c,undefined),b&&b.removeArrayObserver(this,{willChange:"arrangedContentArrayWillChange",didChange:"arrangedContentArrayDidChange"})},"arrangedContent"),_arrangedContentDidChange:Ember.observer(function(){var b=a(this,"arrangedContent"),c=b?a(b,"length"):0;b&&b.addArrayObserver(this,{willChange:"arrangedContentArrayWillChange",didChange:"arrangedContentArrayDidChange"}),this.arrangedContentArrayDidChange(this,0,undefined,c)},"arrangedContent"),objectAt:function(b){return a(this,"content")&&this.objectAtContent(b)},length:Ember.computed(function(){var b=a(this,"arrangedContent");return b?a(b,"length"):0}).property().cacheable(),replace:function(b,c,d){return a(this,"content")&&this.replaceContent(b,c,d),this},arrangedContentArrayWillChange:function(a,b,c,d){this.arrayContentWillChange(b,c,d)},arrangedContentArrayDidChange:function(a,b,c,d){this.arrayContentDidChange(b,c,d)},init:function(){this._super(),this._contentWillChange(),this._contentDidChange(),this._arrangedContentWillChange(),this._arrangedContentDidChange()}})}(),function(){function n(a,b){var c="content."+b,f=b+"WillChange",g=b+"DidChange";a[f]=function(){j(this,b)},a[g]=function(){k(this,b)},d(a,c,null,f),e(a,c,null,g)}function o(a,b){var c="content."+b,d=b+"WillChange",e=b+"DidChange";f(a,c,null,d),g(a,c,null,e),delete a[d],delete a[e]}function p(a,b,c){var d="content."+b,e=b+"WillChange",f=b+"DidChange";h(a,d,null,e,function(){i(a,d,null,f,function(){c.call(a)})})}function q(a,b){var c=l(a,"descs");return c[b]===m}function r(a,b){var c=l(a,"descs");c[b].teardown(a,b),delete c[b],delete a[b]}function s(a,b){if(arguments.length===1)return this.delegateGet(a);p(this,a,function(){this.delegateSet(a,b)})}var a=Ember.get,b=Ember.set,c=Ember.defineProperty,d=Ember.addBeforeObserver,e=Ember.addObserver,f=Ember.removeBeforeObserver,g=Ember.removeObserver,h=Ember._suspendBeforeObserver,i=Ember._suspendObserver,j=Ember.propertyWillChange,k=Ember.propertyDidChange,l=Ember.getMeta,m;m=Ember.computed(s).volatile(),Ember.ObjectProxy=Ember.Object.extend({content:null,_contentDidChange:Ember.observer(function(){},"content"),delegateGet:function(b){var c=a(this,"content");if(c)return a(c,b)},delegateSet:function(c,d){var e=a(this,"content");if(!e)throw new Error("Unable to delegate set without content for property: "+c);return b(e,c,d)},willWatchProperty:function(a){if(a in this)return;c(this,a,m),n(this,a)},didUnwatchProperty:function(a){q(this,a)&&(o(this,a),r(this,a))},unknownProperty:function(a){return this.delegateGet(a)},setUnknownProperty:function(a,b){this.delegateSet(a,b)}})}(),function(){function g(a,b,d,e,f){var g=d._objects,h;g||(g=d._objects={});while(--f>=e){var i=a.objectAt(f);i&&(Ember.addBeforeObserver(i,b,d,"contentKeyWillChange"),Ember.addObserver(i,b,d,"contentKeyDidChange"),h=c(i),g[h]||(g[h]=[]),g[h].push(f))}}function h(a,b,d,e,f){var g=d._objects;g||(g=d._objects={});var h,i;while(--f>=e){var j=a.objectAt(f);j&&(Ember.removeBeforeObserver(j,b,d,"contentKeyWillChange"),Ember.removeObserver(j,b,d,"contentKeyDidChange"),i=c(j),h=g[i],h[h.indexOf(f)]=null)}}var a=Ember.set,b=Ember.get,c=Ember.guidFor,d=Ember.EnumerableUtils.forEach,e=Ember.Object.extend(Ember.Array,{init:function(a,b,c){this._super(),this._keyName=b,this._owner=c,this._content=a},objectAt:function(a){var c=this._content.objectAt(a);return c&&b(c,this._keyName)},length:Ember.computed(function(){var a=this._content;return a?b(a,"length"):0}).property().cacheable()}),f=/^.+:(before|change)$/;Ember.EachProxy=Ember.Object.extend({init:function(a){this._super -(),this._content=a,a.addArrayObserver(this),d(Ember.watchedEvents(this),function(a){this.didAddListener(a)},this)},unknownProperty:function(a,b){var c;return c=new e(this._content,a,this),(new Ember.Descriptor).setup(this,a,c),this.beginObservingContentKey(a),c},arrayWillChange:function(a,b,c,d){var e=this._keys,f,g,i;i=c>0?b+c:-1,Ember.beginPropertyChanges(this);for(f in e){if(!e.hasOwnProperty(f))continue;i>0&&h(a,f,this,b,i),Ember.propertyWillChange(this,f)}Ember.propertyWillChange(this._content,"@each"),Ember.endPropertyChanges(this)},arrayDidChange:function(a,b,c,d){var e=this._keys,f,h,i;i=d>0?b+d:-1,Ember.beginPropertyChanges(this);for(f in e){if(!e.hasOwnProperty(f))continue;i>0&&g(a,f,this,b,i),Ember.propertyDidChange(this,f)}Ember.propertyDidChange(this._content,"@each"),Ember.endPropertyChanges(this)},didAddListener:function(a){f.test(a)&&this.beginObservingContentKey(a.slice(0,-7))},didRemoveListener:function(a){f.test(a)&&this.stopObservingContentKey(a.slice(0,-7))},beginObservingContentKey:function(a){var c=this._keys;c||(c=this._keys={});if(!c[a]){c[a]=1;var d=this._content,e=b(d,"length");g(d,a,this,0,e)}else c[a]++},stopObservingContentKey:function(a){var c=this._keys;if(c&&c[a]>0&&--c[a]<=0){var d=this._content,e=b(d,"length");h(d,a,this,0,e)}},contentKeyWillChange:function(a,b){Ember.propertyWillChange(this,b)},contentKeyDidChange:function(a,b){Ember.propertyDidChange(this,b)}})}(),function(){var a=Ember.get,b=Ember.set,c=Ember.Mixin.create(Ember.MutableArray,Ember.Observable,Ember.Copyable,{get:function(a){return a==="length"?this.length:"number"==typeof a?this[a]:this._super(a)},objectAt:function(a){return this[a]},replace:function(b,c,d){if(this.isFrozen)throw Ember.FROZEN_ERROR;var e=d?a(d,"length"):0;this.arrayContentWillChange(b,c,e);if(!d||d.length===0)this.splice(b,c);else{var f=[b,c].concat(d);this.splice.apply(this,f)}return this.arrayContentDidChange(b,c,e),this},unknownProperty:function(a,b){var c;return b!==undefined&&c===undefined&&(c=this[a]=b),c},indexOf:function(a,b){var c,d=this.length;b===undefined?b=0:b=b<0?Math.ceil(b):Math.floor(b),b<0&&(b+=d);for(c=b;c=0;c--)if(this[c]===a)return c;return-1},copy:function(){return this.slice()}}),d=["length"];Ember.EnumerableUtils.forEach(c.keys(),function(a){Array.prototype[a]&&d.push(a)}),d.length>0&&(c=c.without.apply(c,d)),Ember.NativeArray=c,Ember.A=function(a){return a===undefined&&(a=[]),Ember.NativeArray.apply(a)},Ember.NativeArray.activate=function(){c.apply(Array.prototype),Ember.A=function(a){return a||[]}},Ember.EXTEND_PROTOTYPES&&Ember.NativeArray.activate()}(),function(){var a={},b={};Ember.onLoad=function(c,d){var e;a[c]=a[c]||Ember.A(),a[c].pushObject(d),(e=b[c])&&d(e)},Ember.runLoadHooks=function(c,d){var e;b[c]=d,(e=a[c])&&a[c].forEach(function(a){a(d)})}}(),function(){}(),function(){Ember.ControllerMixin=Ember.Mixin.create({target:null,store:null}),Ember.Controller=Ember.Object.extend(Ember.ControllerMixin)}(),function(){var a=Ember.get,b=Ember.set,c=Ember.EnumerableUtils.forEach;Ember.SortableMixin=Ember.Mixin.create(Ember.MutableEnumerable,{sortProperties:null,sortAscending:!0,addObject:function(b){var c=a(this,"content");c.pushObject(b)},removeObject:function(b){var c=a(this,"content");c.removeObject(b)},orderBy:function(b,d){var e=0,f=a(this,"sortProperties"),g=a(this,"sortAscending");return c(f,function(c){e===0&&(e=Ember.compare(a(b,c),a(d,c)),e!==0&&!g&&(e=-1*e))}),e},destroy:function(){var b=a(this,"content"),d=a(this,"sortProperties");return b&&d&&c(b,function(a){c(d,function(b){Ember.removeObserver(a,b,this,"contentItemSortPropertyDidChange")},this)},this),this._super()},isSorted:Ember.computed("sortProperties",function(){return!!a(this,"sortProperties")}),arrangedContent:Ember.computed("content","sortProperties.@each",function(b,d){var e=a(this,"content"),f=a(this,"isSorted"),g=a(this,"sortProperties"),h=this;return e&&f?(e=e.slice(),e.sort(function(a,b){return h.orderBy(a,b)}),c(e,function(a){c(g,function(b){Ember.addObserver(a,b,this,"contentItemSortPropertyDidChange")},this)},this),Ember.A(e)):e}).cacheable(),_contentWillChange:Ember.beforeObserver(function(){var b=a(this,"content"),d=a(this,"sortProperties");b&&d&&c(b,function(a){c(d,function(b){Ember.removeObserver(a,b,this,"contentItemSortPropertyDidChange")},this)},this),this._super()},"content"),sortAscendingWillChange:Ember.beforeObserver(function(){this._lastSortAscending=a(this,"sortAscending")},"sortAscending"),sortAscendingDidChange:Ember.observer(function(){if(a(this,"sortAscending")!==this._lastSortAscending){var b=a(this,"arrangedContent");b.reverse()}},"sortAscending"),contentArrayWillChange:function(b,d,e,f){var g=a(this,"isSorted");if(g){var h=a(this,"arrangedContent"),i=b.slice(d,d+e),j=a(this,"sortProperties");c(i,function(a){h.removeObject(a),c(j,function(b){Ember.removeObserver(a,b,this,"contentItemSortPropertyDidChange")},this)})}return this._super(b,d,e,f)},contentArrayDidChange:function(b,d,e,f){var g=a(this,"isSorted"),h=a(this,"sortProperties");if(g){var i=b.slice(d,d+f),j=a(this,"arrangedContent");c(i,function(a){this.insertItemSorted(a),c(h,function(b){Ember.addObserver(a,b,this,"contentItemSortPropertyDidChange")},this),this.arrayContentDidChange(d,0,1)},this)}return this._super(b,d,e,f)},insertItemSorted:function(b){var c=a(this,"arrangedContent"),d=a(c,"length"),e=this._binarySearch(b,0,d);c.insertAt(e,b)},contentItemSortPropertyDidChange:function(b){var c=a(this,"arrangedContent"),d=c.indexOf(b);c.removeObject(b),this.insertItemSorted(b)},_binarySearch:function(b,c,d){var e,f,g,h;return c===d?c:(h=a(this,"arrangedContent"),e=c+Math.floor((d-c)/2),f=h.objectAt(e),g=this.orderBy(f,b),g<0?this._binarySearch(b,e+1,d):g>0?this._binarySearch(b,c,e):e)}})}(),function(){var a=Ember.get,b=Ember.set;Ember.ArrayController=Ember.ArrayProxy.extend(Ember.ControllerMixin,Ember.SortableMixin)}(),function(){Ember.ObjectController=Ember.ObjectProxy.extend(Ember.ControllerMixin)}(),function(){}(),function(){}(),function(){var a=Ember.get,b=Ember.set;Ember.Application=Ember.Namespace.extend({rootElement:"body",eventDispatcher:null,customEvents:null,init:function(){var c,d=a(this,"rootElement");this._super(),c=Ember.EventDispatcher.create({rootElement:d}),b(this,"eventDispatcher",c);if(Ember.$.isReady)Ember.run.once(this,this.didBecomeReady);else{var e=this;Ember.$(document).ready(function(){Ember.run.once(e,e.didBecomeReady)})}},initialize:function(c){var d=Ember.A(Ember.keys(this)),e=a(this.constructor,"injections"),f=this,g,h;!c&&Ember.Router.detect(f.Router)&&(c=f.Router.create(),this._createdRouter=c),c&&(b(this,"router",c),b(c,"namespace",this)),Ember.runLoadHooks("application",this),e.forEach(function(a){d.forEach(function(b){a[1](f,c,b)})}),c&&c instanceof Ember.Router&&this.startRouting(c)},didBecomeReady:function(){var b=a(this,"eventDispatcher"),c=a(this,"customEvents");b.setup(c),this.ready()},startRouting:function(b){var c=a(b,"location"),d=a(this,"rootElement"),e=a(b,"applicationController");if(this.ApplicationView&&e){var f=this.ApplicationView.create({controller:e});this._createdApplicationView=f,f.appendTo(d)}b.route(c.getURL()),c.onUpdateURL(function(a){b.route(a)})},ready:Ember.K,willDestroy:function(){a(this,"eventDispatcher").destroy(),this._createdRouter&&this._createdRouter.destroy(),this._createdApplicationView&&this._createdApplicationView.destroy()},registerInjection:function(a){this.constructor.registerInjection(a)}}),Ember.Application.reopenClass({concatenatedProperties:["injections"],injections:Ember.A(),registerInjection:function(b){var c=a(this,"injections"),d=b.before,e=b.name,f=b.injection,g;d?(g=c.find(function(a){if(a[0]===d)return!0}),g=c.indexOf(g)):g=a(c,"length"),c.splice(g,0,[e,f])}}),Ember.Application.registerInjection({name:"controllers",injection:function(a,b,c){if(!/^[A-Z].*Controller$/.test(c))return;var d=c.charAt(0).toLowerCase()+c.substr(1),e=a[c].create();b.set(d,e),e.setProperties({target:b,controllers:b,namespace:a})}})}(),function(){var a=Ember.get,b=Ember.set;Ember.Location={create:function(a){var b=a&&a.implementation,c=this.implementations[b];return c.create.apply(c,arguments)},registerImplementation:function(a,b){this.implementations[a]=b},implementations:{}}}(),function(){var a=Ember.get,b=Ember.set;Ember.HashLocation=Ember.Object.extend({init:function(){b(this,"location",a(this,"location")||window.location)},getURL:function(){return a(this,"location").hash.substr(1)},setURL:function(c){a(this,"location").hash=c,b(this,"lastSetURL",c)},onUpdateURL:function(c){var d=this,e=Ember.guidFor(this);Ember.$(window).bind("hashchange.ember-location-"+e,function(){var e=location.hash.substr(1);if(a(d,"lastSetURL")===e)return;b(d,"lastSetURL",null),c(location.hash.substr(1))})},formatURL:function(a){return"#"+a},willDestroy:function(){var a=Ember.guidFor(this);Ember.$(window).unbind("hashchange.ember-location-"+a)}}),Ember.Location.registerImplementation("hash",Ember.HashLocation)}(),function(){var a=Ember.get,b=Ember.set;Ember.HistoryLocation=Ember.Object.extend({init:function(){b(this,"location",a(this,"location")||window.location),b(this,"_initialURL",a(this,"location").pathname)},_initialURL:null,getURL:function(){return a(this,"location").pathname},setURL:function(c){var d=window.history.state,e=a(this,"_initialURL");c===""&&(c="/");if(e&&e!==c||d&&d.path!==c)b(this,"_initialURL",null),window.history.pushState({path:c},null,c)},onUpdateURL:function(a){var b=Ember.guidFor(this);Ember.$(window).bind("popstate.ember-location-"+b,function(b){a(location.pathname)})},formatURL:function(a){return a},willDestroy:function(){var a=Ember.guidFor(this);Ember.$(window).unbind("popstate.ember-location-"+a)}}),Ember.Location.registerImplementation("history",Ember.HistoryLocation)}(),function(){var a=Ember.get,b=Ember.set;Ember.NoneLocation=Ember.Object.extend({path:"",getURL:function(){return a(this,"path")},setURL:function(a){b(this,"path",a)},onUpdateURL:function(a){},formatURL:function(a){return a}}),Ember.Location.registerImplementation("none",Ember.NoneLocation)}(),function(){}(),function(){}(),function(){Ember.$=window.jQuery}(),function(){var a=Ember.get,b=Ember.set,c=Ember.ArrayPolyfills.indexOf,d=function(){this.seen={},this.list=[]};d.prototype={add:function(a){if(a in this.seen)return;this.seen[a]=!0,this.list.push(a)},toDOM:function(){return this.list.join(" ")}},Ember.RenderBuffer=function(a){return new Ember._RenderBuffer(a)},Ember._RenderBuffer=function(a){this.elementTag=a,this.childBuffers=[]},Ember._RenderBuffer.prototype={elementClasses:null,elementId:null,elementAttributes:null,elementTag:null,elementStyle:null,parentBuffer:null,push:function(a){return this.childBuffers.push(String(a)),this},addClass:function(a){var b=this.elementClasses=this.elementClasses||new d;return this.elementClasses.add(a),this},id:function(a){return this.elementId=a,this},attr:function(a,b){var c=this.elementAttributes=this.elementAttributes||{};return arguments.length===1?c[a]:(c[a]=b,this)},removeAttr:function(a){var b=this.elementAttributes;return b&&delete b[a],this},style:function(a,b){var c=this.elementStyle=this.elementStyle||{};return this.elementStyle[a]=b,this},newBuffer:function(a,b,c,d){var e=new Ember._RenderBuffer(a);return e.parentBuffer=b,d&&Ember.$.extend(e,d),c&&c.call(this,e),e},replaceWithBuffer:function(a){var b=this.parentBuffer;if(!b)return;var d=b.childBuffers,e=c.call(d,this);a?d.splice(e,1,a):d.splice(e,1)},begin:function(a){return this.newBuffer(a,this,function(a){this.childBuffers.push(a)})},prepend:function(a){return this.newBuffer(a,this,function(a){this.childBuffers.splice(0,0,a)})},replaceWith:function(a){var b=this.parentBuffer;return this.newBuffer(a,b,function(a){this.replaceWithBuffer(a)})},insertAfter:function(b){var d=a(this,"parentBuffer");return this.newBuffer(b,d,function(a){var b=d.childBuffers,e=c.call(b,this);b.splice(e+1,0,a)})},end:function(){var a=this.parentBuffer;return a||this},remove:function(){this.replaceWithBuffer(null)},element:function(){return Ember.$(this.string())[0]},string:function(){var a="",b=this.elementTag,c;if(b){var d=this.elementId,e=this.elementClasses,f=this.elementAttributes,g=this.elementStyle,h="",i;c=["<"+b],d&&c.push('id="'+this._escapeAttribute(d)+'"'),e&&c.push('class="'+this._escapeAttribute(e.toDOM())+'"');if(g){for(i in g)g.hasOwnProperty(i)&&(h+=i+":"+this._escapeAttribute(g[i])+";");c.push('style="'+h+'"')}if(f)for(i in f)f.hasOwnProperty(i)&&c.push(i+'="'+this._escapeAttribute(f[i])+'"');c=c.join(" ")+">"}var j=this.childBuffers;return Ember.ArrayPolyfills.forEach.call(j,function(b){var c=typeof b=="string";a+=c?b:b.string()}),b?c+a+"":a},_escapeAttribute:function(a){var b={"<":"<",">":">",'"':""","'":"'","`":"`"},c=/&(?!\w+;)|[<>"'`]/g,d=/[&<>"'`]/,e=function(a){return b[a]||"&"},f=a.toString();return d.test(f)?f.replace(c,e):f}}}(),function(){var a=Ember.get,b=Ember.set,c=Ember.String.fmt;Ember.EventDispatcher=Ember.Object.extend({rootElement:"body",setup:function(b){var c,d={touchstart:"touchStart",touchmove:"touchMove",touchend:"touchEnd",touchcancel:"touchCancel",keydown:"keyDown",keyup:"keyUp",keypress:"keyPress",mousedown:"mouseDown",mouseup:"mouseUp",contextmenu:"contextMenu",click:"click",dblclick:"doubleClick",mousemove:"mouseMove",focusin:"focusIn",focusout:"focusOut",mouseenter:"mouseEnter",mouseleave:"mouseLeave",submit:"submit",input:"input",change:"change",dragstart:"dragStart",drag:"drag",dragenter:"dragEnter",dragleave:"dragLeave",dragover:"dragOver",drop:"drop",dragend:"dragEnd"};Ember.$.extend(d,b||{});var e=Ember.$(a(this,"rootElement"));e.addClass("ember-application");for(c in d)d.hasOwnProperty(c)&&this.setupHandler(e,c,d[c])},setupHandler:function(a,b,c){var d=this;a.delegate(".ember-view",b+".ember",function(a,b){var e=Ember.View.views[this.id],f=!0,g=null;return g=d._findNearestEventManager(e,c),g&&g!==b?f=d._dispatchEvent(g,a,c,e):e?f=d._bubbleEvent(e,a,c):a.stopPropagation(),f}),a.delegate("[data-ember-action]",b+".ember",function(a){var b=Ember.$(a.currentTarget).attr("data-ember-action"),d=Ember.Handlebars.ActionHelper.registeredActions[b],e=d.handler;if(d.eventName===c)return a.preventDefault(),e(a)})},_findNearestEventManager:function(b,c){var d=null;while(b){d=a(b,"eventManager");if(d&&d[c])break;b=a(b,"parentView")}return d},_dispatchEvent:function(a,b,c,d){var e=!0,f=a[c];return Ember.typeOf(f)==="function"?(e=f.call(a,b,d),b.stopPropagation()):e=this._bubbleEvent(d,b,c),e},_bubbleEvent:function(a,b,c){return Ember.run(function(){return a.handleEvent(c,b)})},destroy:function(){var b=a(this,"rootElement");return Ember.$(b).undelegate(".ember").removeClass("ember-application"),this._super()}})}(),function(){var a=Ember.run.queues;a.splice(Ember.$.inArray("actions",a)+1,0,"render")}(),function(){var a=Ember.get,b=Ember.set;Ember.ControllerMixin.reopen({target:null,controllers:null,namespace:null,view:null,connectOutlet:function(c,d){var e,f,g,h,i;arguments.length===1?Ember.typeOf(c)==="object"&&(i=c,e=i.outletName,c=i.name,f=i.viewClass,h=i.controller,d=i.context):i={},e=e||"view";if(c){var j=a(this,"namespace"),k=a(this,"controllers"),l=c.charAt(0).toUpperCase()+c.substr(1)+"View";f=a(j,l),h=a(k,c+"Controller")}return h&&d&&h.set("content",d),g=f.create(),h&&b(g,"controller",h),b(this,e,g),g}})}(),function(){}(),function(){var a=Ember.get,b=Ember.set,c=Ember.addObserver,d=Ember.getPath,e=Ember.meta,f=Ember.String.fmt,g=[].slice,h=Ember.EnumerableUtils.forEach,i=Ember.computed(function(){var b=a(this,"_childViews"),c=Ember.A();return h(b,function(b){b.isVirtual?c.pushObjects(a(b,"childViews")):c.push(b)}),c}).property().cacheable(),j=Ember.VIEW_PRESERVES_CONTEXT;Ember.TEMPLATES={};var k={preRender:{},inBuffer:{},hasElement:{},inDOM:{},destroyed:{}};Ember.View=Ember.Object.extend(Ember.Evented,{concatenatedProperties:["classNames","classNameBindings","attributeBindings"],isView:!0,templateName:null,layoutName:null,templates:Ember.TEMPLATES,template:Ember.computed(function(b,c){if(c!==undefined)return c;var d=a(this,"templateName"),e=this.templateForName(d,"template");return e||a(this,"defaultTemplate")}).property("templateName").cacheable(),controller:Ember.computed(function(b,c){var d;return arguments.length===2?c:(d=a(this,"parentView"),d?a(d,"controller"):null)}).property().cacheable(),layout:Ember.computed(function(b,c){if(arguments.length===2)return c;var d=a(this,"layoutName"),e=this.templateForName(d,"layout");return e||a(this,"defaultLayout")}).property("layoutName").cacheable(),templateForName:function(b,c){if(!b)return;var d=a(this,"templates"),e=a(d,b);if(!e)throw new Ember.Error(f('%@ - Unable to find %@ "%@".',[this,c,b]));return e},context:Ember.computed(function(c,d){return arguments.length===2?(b(this,"_context",d),d):a(this,"_context")}).cacheable(),_context:Ember.computed(function(b,c){var d,e;if(arguments.length===2)return c;if(j){if(e=a(this,"controller"))return e;d=a(this,"_parentView");if(d)return a(d,"_context")}return this}).cacheable(),_displayPropertyDidChange:Ember.observer(function(){this.rerender()},"context","controller"),parentView:Ember.computed(function(){var b=a(this,"_parentView");return b&&b.isVirtual?a(b,"parentView"):b}).property("_parentView").volatile(),_parentView:null,concreteView:Ember.computed(function(){return this.isVirtual?a(this,"parentView"):this}).property("_parentView").volatile(),isVisible:!0,childViews:i,_childViews:[],_childViewsWillChange:Ember.beforeObserver(function(){if(this.isVirtual){var b=a(this,"parentView");b&&Ember.propertyWillChange(b,"childViews")}},"childViews"),_childViewsDidChange:Ember.observer(function(){if(this.isVirtual){var b=a(this,"parentView");b&&Ember.propertyDidChange(b,"childViews")}},"childViews"),nearestInstanceOf:function(b){var c=a(this,"parentView");while(c){if(c instanceof b)return c;c=a(c,"parentView")}},nearestWithProperty:function(b){var c=a(this,"parentView");while(c){if(b in c)return c;c=a(c,"parentView")}},nearestChildOf:function(b){var c=a(this,"parentView");while(c){if(a(c,"parentView")instanceof b)return c;c=a(c,"parentView")}},collectionView:Ember.computed(function(){return this.nearestInstanceOf(Ember.CollectionView)}).cacheable(),itemView:Ember.computed(function(){return this.nearestChildOf(Ember.CollectionView)}).cacheable(),contentView:Ember.computed(function(){return this.nearestWithProperty("content")}).cacheable(),_parentViewDidChange:Ember.observer(function(){if(this.isDestroying)return;this.invokeRecursively(function(a){a.propertyDidChange("collectionView"),a.propertyDidChange("itemView"),a.propertyDidChange("contentView")}),d(this,"parentView.controller")&&!a(this,"controller")&&this.notifyPropertyChange("controller")},"_parentView"),_controllerDidChange:Ember.observer(function(){if(this.isDestroying)return;this.forEachChildView(function(a){a.propertyDidChange("controller")})},"controller"),cloneKeywords:function(){var b=a(this,"templateData"),c=b?Ember.copy(b.keywords):{};return c.view=a(this,"concreteView"),c.controller=a(this,"controller"),c},render:function(b){var c=a(this,"layout")||a(this,"template");if(c){var d=a(this,"_context"),e=this.cloneKeywords(),f={view:this,buffer:b,isRenderData:!0,keywords:e},g=c(d,{data:f});g!==undefined&&b.push(g)}},invokeForState:function(a){var b=this.state,c,d;if(d=k[b][a])return c=g.call(arguments),c[0]=this,d.apply(this,c);var e=this,f=e.states,h;while(f){h=f[b];while(h){d=h[a];if(d)return k[b][a]=d,c=g.call(arguments,1),c.unshift(this),d.apply(this,c);h=h.parentState}f=f.parent}},rerender:function(){return this.invokeForState("rerender")},clearRenderedChildren:function(){var b=this.lengthBeforeRender,c=this.lengthAfterRender,d=a(this,"_childViews");for(var e=c-1;e>=b;e--)d[e]&&d[e].destroy()},_applyClassNameBindings:function(){var b=a(this,"classNameBindings"),d=a(this,"classNames"),e,f,g;if(!b)return;h(b,function(a){var b,h,i=function(){f=this._classStringForProperty(a),e=this.$(),b&&(e.removeClass(b),d.removeObject(b)),f?(e.addClass(f),b=f):b=null};g=this._classStringForProperty(a),g&&(d.push(g),b=g),h=a.split(":")[0],c(this,h,i)},this)},_applyAttributeBindings:function(b){var d=a(this,"attributeBindings"),e,f,g;if(!d)return;h(d,function(d){var g=d.split(":"),h=g[0],i=g[1]||h,j=function(){f=this.$(),e=a(this,h),Ember.View.applyAttributeBindings(f,i,e)};c(this,h,j),e=a(this,h),Ember.View.applyAttributeBindings(b,i,e)},this)},_classStringForProperty:function(a){var b=a.split(":"),c=b[1];a=b[0];var d=Ember.getPath(this,a,!1);d===undefined&&Ember.isGlobalPath(a)&&(d=Ember.getPath(window,a));if(!!d&&c)return c;if(d===!0){var e=a.split(".");return Ember.String.dasherize(e[e.length-1])}return d!==!1&&d!==undefined&&d!==null?d:null},element:Ember.computed(function(a,b){return b!==undefined?this.invokeForState("setElement",b):this.invokeForState("getElement")}).property("_parentView").cacheable(),$:function(a){return this.invokeForState("$",a)},mutateChildViews:function(b){var c=a(this,"_childViews"),d=a(c,"length"),e;while(--d>=0)e=c[d],b.call(this,e,d);return this},forEachChildView:function(b){var c=a(this,"_childViews");if(!c)return this;var d=a(c,"length"),e,f;for(f=0;f=0;h--)c[h].removedFromDOM=!0,c[h].destroy();delete Ember.View.views[a(this,"elementId")]},createChildView:function(c,d){return Ember.View.detect(c)?(d=d||{},d._parentView=this,d.templateData=d.templateData||a(this,"templateData"),c=c.create(d),c.viewName&&b(a(this,"concreteView"),c.viewName,c)):(a(c,"templateData")||b(c,"templateData",a(this,"templateData")),b(c,"_parentView",this)),c},becameVisible:Ember.K,becameHidden:Ember.K,_isVisibleDidChange:Ember.observer(function(){var b=a(this,"isVisible");this.$().toggle(b);if(this._isAncestorHidden())return;b?this._notifyBecameVisible():this._notifyBecameHidden()},"isVisible"),_notifyBecameVisible:function(){this.trigger("becameVisible"),this.forEachChildView(function(b){var c=a(b,"isVisible");(c||c===null)&&b._notifyBecameVisible()})},_notifyBecameHidden:function(){this.trigger("becameHidden"),this.forEachChildView(function(b){var c=a(b,"isVisible");(c||c===null)&&b._notifyBecameHidden()})},_isAncestorHidden:function(){var b=a(this,"parentView");while(b){if(a(b,"isVisible")===!1)return!0;b=a(b,"parentView")}return!1},clearBuffer:function(){this.invokeRecursively(function(a){this.buffer=null})},transitionTo:function(a,b){this.state=a,b!==!1&&this.forEachChildView(function(b){b.transitionTo(a)})},trigger:function(a){this._super.apply(this,arguments);if(this[a])return this[a].apply(this,[].slice.call(arguments,1))},has:function(a){return Ember.typeOf(this[a])==="function"||this._super(a)},handleEvent:function(a,b){return this.invokeForState("handleEvent",a,b)}});var l={prepend:function(a,b){b._insertElementLater(function(){var c=a.$();c.prepend(b.$())})},after:function(a,b){b._insertElementLater(function(){var c=a.$();c.after(b.$())})},replace:function(c){var d=a(c,"element");b(c,"element",null),c._insertElementLater(function(){Ember.$(d).replaceWith(a(c,"element"))})},remove:function(c){var d=a(c,"element");b(c,"element",null),c._lastInsert=null,Ember.$(d).remove()},empty:function(a){a.$().empty()}};Ember.View.reopen({states:Ember.View.states,domManager:l}),Ember.View.views={},Ember.View.childViewsProperty=i,Ember.View.applyAttributeBindings=function(a,b,c){var d=Ember.typeOf(c),e=a.attr(b);(d==="string"||d==="number"&&!isNaN(c))&&c!==e?a.attr(b,c):c&&d==="boolean"?a.attr(b,b):c||a.removeAttr(b)}}(),function(){var a=Ember.get,b=Ember.set;Ember.View.states={_default:{appendChild:function(){throw"You can't use appendChild outside of the rendering process"},$:function(){return Ember.$()},getElement:function(){return null},handleEvent:function(){return!0},destroyElement:function(a){return b(a,"element",null),a._lastInsert=null,a}}},Ember.View.reopen({states:Ember.View.states})}(),function(){Ember.View.states.preRender={parentState:Ember.View.states._default,insertElement:function(a,b){if(a._lastInsert!==Ember.guidFor(b))return;a.createElement(),a._notifyWillInsertElement(),b.call(a),a.transitionTo("inDOM"),a._notifyDidInsertElement()},empty:Ember.K,setElement:function(a,b){return a.beginPropertyChanges(),a.invalidateRecursively("element"),b!==null&&a.transitionTo("hasElement"),a.endPropertyChanges(),b}}}(),function(){var a=Ember.get,b=Ember.set,c=Ember.meta;Ember.View.states.inBuffer={parentState:Ember.View.states._default,$:function(a,b){return a.rerender(),Ember.$()},rerender:function(a){a._notifyWillRerender(),a.clearRenderedChildren(),a.renderToBuffer(a.buffer,"replaceWith")},appendChild:function(b,c,d){var e=b.buffer;return c=this.createChildView(c,d),a(b,"_childViews").push(c),c.renderToBuffer(e),b.propertyDidChange("childViews"),c},destroyElement:function(a){return a.clearBuffer(),a._notifyWillDestroyElement(),a.transitionTo("preRender"),a},empty:function(){},insertElement:function(){throw"You can't insert an element that has already been rendered"},setElement:function(a,b){return a.invalidateRecursively("element"),b===null?a.transitionTo("preRender"):(a.clearBuffer(),a.transitionTo("hasElement")),b}}}(),function(){var a=Ember.get,b=Ember.set,c=Ember.meta;Ember.View.states.hasElement={parentState:Ember.View.states._default,$:function(b,c){var d=a(b,"element");return c?Ember.$(c,d):Ember.$(d)},getElement:function(b){var c=a(b,"parentView");return c&&(c=a(c,"element")),c?b.findElementInParentElement(c):Ember.$("#"+a(b,"elementId"))[0]},setElement:function(a,b){if(b!==null)throw"You cannot set an element to a non-null value when the element is already in the DOM.";return a.invalidateRecursively("element"),a.transitionTo("preRender"),b},rerender:function(a){return a._notifyWillRerender(),a.clearRenderedChildren(),a.domManager.replace(a),a},destroyElement:function(a){return a._notifyWillDestroyElement(),a.domManager.remove(a),a},empty:function(b){var c=a(b,"_childViews"),d,e;if(c){d=a(c,"length");for(e=0;e=c;h--)g=f[h],j&&(g.removedFromDOM=!0),g.destroy()},arrayDidChange:function(c,d,e,f){var g=a(this,"itemViewClass"),h=a(this,"childViews"),i=[],j,k,l,m,n;"string"==typeof g&&(g=Ember.getPath(g)),m=c?a(c,"length"):0;if(m)for(l=d;l0&&k[0]===h[0])g=k.shift(),h.shift();f.pathsCache[b]={exitStates:h,enterStates:k,resolveState:g}}n=k.length-1;while(e.length>0){if(n>=0)l=k[n--];else{l=k[0]?a(k[0],"parentState"):g;if(!l)throw"Cannot match all contexts to states";k.unshift(l),h.unshift(l)}o=d&&a(l,"hasContext"),i.unshift(o?e.pop():null)}if(k.length>0){l=k[k.length-1];for(;;){m=a(l,"initialState")||"start",l=c(l,"states."+m);if(!l)break;k.push(l),i.push(undefined)}while(k.length>0){if(k[0]!==h[0])break;if(k.length===i.length){if(this.getStateMeta(k[0],"context")!==i[0])break;i.shift()}g=k.shift(),h.shift()}}}this.enterState(h,k,k[k.length-1]||g),this.triggerSetupContext(k,i)},triggerSetupContext:function(b,c){var d=b.length-c.length;e.call(b,function(b,e){b.trigger(a(this,"transitionEvent"),this,c[e-d])},this)},getState:function(b){var c=a(this,b),d=a(this,"parentState");if(c)return c;if(d)return d.getState(b)},enterState:function(c,d,f){var g=this.enableLogging,h=this;c=c.slice(0).reverse(),e.call(c,function(a){a.trigger("exit",h)}),e.call(d,function(b){g&&Ember.Logger.log("STATEMANAGER: Entering "+a(b,"path")),b.trigger("enter",h)}),b(this,"currentState",f)}})}(),function(){}(),function(){var a=Ember.get,b=Ember.getPath,c=function(a){var b=a.toString(),c=b.split("."),d=c[c.length-1];return Ember.String.underscore(d)+"_id"},d=function(a,b){for(var c in b){if(!b.hasOwnProperty(c))continue;if(a.hasOwnProperty(c))continue;a[c]=b[c]}};Ember.Routable=Ember.Mixin.create({init:function(){var b;this.on("connectOutlets",this,this.stashContext);if(b=a(this,"redirectsTo"))this.connectOutlets=function(a){a.transitionTo(b)};var c=a(this,"route");c===""&&(c="/"),this._super()},stashContext:function(b,c){var d=this.serialize(b,c);b.setStateMeta(this,"context",c),b.setStateMeta(this,"serialized",d),a(this,"isRoutable")&&!a(b,"isRouting")&&this.updateRoute(b,a(b,"location"))},updateRoute:function(b,c){if(a(this,"isLeafRoute")){var d=this.absoluteRoute(b);c.setURL(d)}},absoluteRoute:function(b,c){var e=a(this,"parentState"),f="",g;a(e,"isRoutable")&&(f=e.absoluteRoute(b,c));var h=a(this,"routeMatcher"),i=b.getStateMeta(this,"serialized");return c=c||{},d(c,i),g=h&&h.generate(c),g&&(f=f+"/"+g),f},isRoutable:Ember.computed(function(){return typeof a(this,"route")=="string"}).cacheable(),isLeafRoute:Ember.computed(function(){return a(this,"isLeaf")?!0:!a(this,"childStates").findProperty("isRoutable")}).cacheable(),routeMatcher:Ember.computed(function(){var b=a(this,"route");if(b)return Ember._RouteMatcher.create({route:b})}).cacheable(),hasContext:Ember.computed(function(){var b=a(this,"routeMatcher");if(b)return b.identifiers.length>0}).cacheable(),modelClass:Ember.computed(function(){var b=a(this,"modelType");return typeof b=="string"?Ember.getPath(window,b):b}).cacheable(),modelClassFor:function(b){var c,d,e,f,g;if(c=a(this,"modelClass"))return c;if(!b)return;d=a(this,"routeMatcher");if(!d)return;e=d.identifiers;if(e.length!==2)return;f=e[1].match(/^(.*)_id$/);if(!f)return;return g=Ember.String.classify(f[1]),a(b,g)},deserialize:function(b,d){var e,f,g;return(e=this.modelClassFor(a(b,"namespace")))?e.find(d[c(e)]):d},serialize:function(b,d){var e,f,g,h,i;if(Ember.empty(d))return"";if(e=this.modelClassFor(a(b,"namespace")))h=c(e),i=a(d,"id"),d={},d[h]=i;return d},routePath:function(c,d){if(a(this,"isLeafRoute"))return;var e=a(this,"childStates"),f;e=Ember.A(e.filterProperty("isRoutable")),e=e.sort(function(c,d){var e=b(c,"routeMatcher.identifiers.length"),f=b(d,"routeMatcher.identifiers.length"),g=a(c,"route"),h=a(d,"route");return g.indexOf(h)===0?-1:h.indexOf(g)===0?1:e!==f?e-f:b(d,"route.length")-b(c,"route.length")});var g=e.find(function(b){var c=a(b,"routeMatcher");if(f=c.match(d))return!0}),h=g.deserialize(c,f.hash);c.transitionTo(a(g,"path"),h),c.send("routePath",f.remaining)},unroutePath:function(b,c){if(a(this,"parentState")===b)return;c=c.replace(/^(?=[^\/])/,"/");var d=this.absoluteRoute(b),e=a(this,"route");if(e!=="/"){var f=c.indexOf(d),g=c.charAt(d.length);if(f===0&&(g==="/"||g===""))return}var h=a(a(this,"parentState"),"path");b.transitionTo(h),b.send("unroutePath",c)},connectOutlets:Ember.K,navigateAway:Ember.K})}(),function(){Ember.Route=Ember.State.extend(Ember.Routable)}(),function(){var a=function(a){return a.replace(/[\-\[\]{}()*+?.,\\\^\$|#\s]/g,"\\$&")};Ember._RouteMatcher=Ember.Object.extend({state:null,init:function(){var b=this.route,c=[],d=1,e;b.charAt(0)==="/"&&(b=this.route=b.substr(1)),e=a(b);var f=e.replace(/:([a-z_]+)(?=$|\/)/gi,function(a,b){return c[d++]=b,"([^/]+)"});this.identifiers=c,this.regex=new RegExp("^/?"+f)},match:function(a){var b=a.match(this.regex);if(b){var c=this.identifiers,d={};for(var e=1,f=c.length;e0?d:null}}},generate:function(a){var b=this.identifiers,c=this.route,d;for(var e=1,f=b.length;e"},p=function(){return""};if(e)h=function(a,b){var c=d.createRange(),e=d.getElementById(a.start),f=d.getElementById(a.end);return b?(c.setStartBefore(e),c.setEndAfter(f)):(c.setStartAfter(e),c.setEndBefore(f)),c},i=function(a,b){var c=h(this,b);c.deleteContents();var d=c.createContextualFragment(a);c.insertNode(d)},j=function(){var a=h(this,!0);a.deleteContents()},l=function(a){var b=d.createRange();b.setStart(a),b.collapse(!1);var c=b.createContextualFragment(this.outerHTML());a.appendChild(c)},m=function(a){var b=d.createRange(),c=d.getElementById(this.end);b.setStartAfter(c),b.setEndAfter(c);var e=b.createContextualFragment(a);b.insertNode(e)},n=function(a){var b=d.createRange(),c=d.getElementById(this.start);b.setStartAfter(c),b.setEndAfter(c);var e=b.createContextualFragment(a);b.insertNode(e)};else{var q={select:[1,""],fieldset:[1,"
                  ","
                  "],table:[1,"","
                  "],tbody:[2,"","
                  "],tr:[3,"","
                  "],colgroup:[2,"","
                  "],map:[1,"",""],_default:[0,"",""]},r=function(a,b){var c=q[a.tagName.toLowerCase()]||q._default,e=c[0],g=c[1],h=c[2];f&&(b="­"+b);var i=d.createElement("div");i.innerHTML=g+b+h;for(var j=0;j<=e;j++)i=i.firstChild;if(f){var k=i;while(k.nodeType===1&&!k.nodeName)k=k.firstChild;k.nodeType===3&&k.nodeValue.charAt(0)==="­"&&(k.nodeValue=k.nodeValue.slice(1))}return i},s=function(a){while(a.parentNode.tagName==="")a=a.parentNode;return a},t=function(a,b){a.parentNode!==b.parentNode&&b.parentNode.insertBefore(a,b.parentNode.firstChild)};i=function(a,b){var c=s(d.getElementById(this.start)),e=d.getElementById(this.end),f=e.parentNode,g,h,i;t(c,e),g=c.nextSibling;while(g){h=g.nextSibling,i=g===e;if(i){if(!b)break;e=g.nextSibling}g.parentNode.removeChild(g);if(i)break;g=h}g=r(c.parentNode,a);while(g)h=g.nextSibling,f.insertBefore(g,e),g=h},j=function(){var a=s(d.getElementById(this.start)),b=d.getElementById(this.end);this.html(""),a.parentNode.removeChild(a),b.parentNode.removeChild(b)},l=function(a){var b=r(a,this.outerHTML());while(b)nextSibling=b.nextSibling,a.appendChild(b),b=nextSibling},m=function(a){var b=d.getElementById(this.end),c=b.nextSibling,e=b.parentNode,f,g;g=r(e,a);while(g)f=g.nextSibling,e.insertBefore(g,c),g=f},n=function(a){var b=d.getElementById(this.start),c=b.parentNode,e,f;f=r(c,a);var g=b.nextSibling;while(f)e=f.nextSibling,c.insertBefore(f,g),f=e}}g.prototype.html=function(a){this.checkRemoved();if(a===undefined)return this.innerHTML;i.call(this,a),this.innerHTML=a},g.prototype.replaceWith=function(a){this.checkRemoved(),i.call(this,a,!0)},g.prototype.remove=j,g.prototype.outerHTML=k,g.prototype.appendTo=l,g.prototype.after=m,g.prototype.prepend=n,g.prototype.startTag=o,g.prototype.endTag=p,g.prototype.isRemoved=function(){var a=d.getElementById(this.start),b=d.getElementById(this.end);return!a||!b},g.prototype.checkRemoved=function(){if(this.isRemoved())throw new Error("Cannot perform operations on a Metamorph that is not in the DOM.")},a.Metamorph=g})(this)}(),function(){var a=Ember.create;Ember.Handlebars=a(Handlebars),Ember.Handlebars.helpers=a(Handlebars.helpers),Ember.Handlebars.Compiler=function(){},Ember.Handlebars.Compiler.prototype=a(Handlebars.Compiler.prototype),Ember.Handlebars.Compiler.prototype.compiler=Ember.Handlebars.Compiler,Ember.Handlebars.JavaScriptCompiler=function(){},Ember.Handlebars.JavaScriptCompiler.prototype=a(Handlebars.JavaScriptCompiler.prototype),Ember.Handlebars.JavaScriptCompiler.prototype.compiler=Ember.Handlebars.JavaScriptCompiler,Ember.Handlebars.JavaScriptCompiler.prototype.namespace="Ember.Handlebars",Ember.Handlebars.JavaScriptCompiler.prototype.initializeBuffer=function(){return"''"},Ember.Handlebars.JavaScriptCompiler.prototype.appendToBuffer=function(a){return"data.buffer.push("+a+");"},Ember.Handlebars.Compiler.prototype.mustache=function(a){if(a.params.length||a.hash)return Handlebars.Compiler.prototype.mustache.call(this,a);var b=new Handlebars.AST.IdNode(["_triageMustache"]);return a.escaped||(a.hash=a.hash||new Handlebars.AST.HashNode([]),a.hash.pairs.push(["unescaped",new Handlebars.AST.StringNode("true")])),a=new Handlebars.AST.MustacheNode([b].concat([a.id]),a.hash,!a.escaped),Handlebars.Compiler.prototype.mustache.call(this,a)},Ember.Handlebars.precompile=function(a){var b=Handlebars.parse(a),c={knownHelpers:{action:!0,unbound:!0,bindAttr:!0,template:!0,view:!0,_triageMustache:!0},data:!0,stringParams:!0},d=(new Ember.Handlebars.Compiler).compile(b,c);return(new Ember.Handlebars.JavaScriptCompiler).compile(d,c,undefined,!0)},Ember.Handlebars.compile=function(a){var b=Handlebars.parse(a),c={data:!0,stringParams:!0},d=(new Ember.Handlebars.Compiler).compile(b,c),e=(new Ember.Handlebars.JavaScriptCompiler).compile(d,c,undefined,!0);return Handlebars.template(e)};var b=Ember.Handlebars.normalizePath=function(a,b,c){var d=c&&c.keywords||{},e,f;return e=b.split(".",1)[0],d.hasOwnProperty(e)&&(a=d[e],f=!0,b===e?b="":b=b.substr(e.length+1)),{root:a,path:b,isKeyword:f}};Ember.Handlebars.getPath=function(a,c,d){var e=d&&d.data,f=b(a,c,e),g;return a=f.root,c=f.path,g=Ember.getPath(a,c),g===undefined&&a!==window&&Ember.isGlobalPath(c)&&(g=Ember.getPath(window,c)),g},Ember.Handlebars.registerHelper("helperMissing",function(a,b){var c,d="";throw c="%@ Handlebars error: Could not find property '%@' on object %@.",b.data&&(d=b.data.view),new Ember.Error(Ember.String.fmt(c,[d,a,this]))})}(),function(){Ember.String.htmlSafe=function(a){return new Handlebars.SafeString(a)};var a=Ember.String.htmlSafe;Ember.EXTEND_PROTOTYPES&&(String.prototype.htmlSafe=function(){return a(this)})}(),function(){var a=Ember.set,b=Ember.get,c=Ember.getPath,d={remove:function(b){var c=b.morph;if(c.isRemoved())return;a(b,"element",null),b._lastInsert=null,c.remove()},prepend:function(a,b){b._insertElementLater(function(){var c=a.morph;c.prepend(b.outerHTML),b.outerHTML=null})},after:function(a,b){b._insertElementLater(function(){var c=a.morph;c.after(b.outerHTML),b.outerHTML=null})},replace:function(a){var c=a.morph;a.transitionTo("preRender"),a.clearRenderedChildren();var d=a.renderToBuffer();Ember.run.schedule("render",this,function(){if(b(a,"isDestroyed"))return;a.invalidateRecursively("element"),a._notifyWillInsertElement(),c.replaceWith(d.string()),a.transitionTo("inDOM"),a._notifyDidInsertElement()})},empty:function(a){a.morph.html("")}};Ember._Metamorph=Ember.Mixin.create({isVirtual:!0,tagName:"",init:function(){this._super(),this.morph=Metamorph()},beforeRender:function(a){a.push(this.morph.startTag())},afterRender:function(a){a.push(this.morph.endTag())},createElement:function(){var a=this.renderToBuffer();this.outerHTML=a.string(),this.clearBuffer()},domManager:d}),Ember._MetamorphView=Ember.View.extend(Ember._Metamorph)}(),function(){var a=Ember.get,b=Ember.set,c=Ember.Handlebars.getPath;Ember._HandlebarsBoundView=Ember._MetamorphView.extend({shouldDisplayFunc:null,preserveContext:!1,previousContext:null,displayTemplate:null,inverseTemplate:null,path:null,pathRoot:null,normalizedValue:Ember.computed(function(){var b=a(this,"path"),d=a(this,"pathRoot"),e=a(this,"valueNormalizerFunc"),f,g;return b===""?f=d:(g=a(this,"templateData"),f=c(d,b,{data:g})),e?e(f):f}).property("path","pathRoot","valueNormalizerFunc").volatile(),rerenderIfNeeded:function(){!a(this,"isDestroyed")&&a(this,"normalizedValue")!==this._lastNormalizedValue&&this.rerender()},render:function(c){var d=a(this,"isEscaped"),e=a(this,"shouldDisplayFunc"),f=a(this,"preserveContext"),g=a(this,"previousContext"),h=a(this,"inverseTemplate"),i=a(this,"displayTemplate"),j=a(this,"normalizedValue");this._lastNormalizedValue=j;if(e(j)){b(this,"template",i);if(f)b(this,"_context",g);else{if(!i){j===null||j===undefined?j="":j instanceof Handlebars.SafeString||(j=String(j)),d&&(j=Handlebars.Utils.escapeExpression(j)),c.push(j);return}b(this,"_context",j)}}else h?(b(this,"template",h),f?b(this,"_context",g):b(this,"_context",j)):b(this,"template",function(){return""});return this._super(c)}})}(),function(){var a=Ember.get,b=Ember.set,c=Ember.String.fmt,d=Ember.Handlebars.getPath,e=Ember.Handlebars.normalizePath,f=Ember.ArrayPolyfills.forEach,g=Ember.Handlebars,h=g.helpers,i=function(a,b,c,f,g){var h=b.data,i=b.fn,j=b.inverse,k=h.view,l=this,m,n,o;o=e(l,a,h),m=o.root,n=o.path;if("object"==typeof this){var p=k.createChildView(Ember._HandlebarsBoundView,{preserveContext:c,shouldDisplayFunc:f,valueNormalizerFunc:g,displayTemplate:i,inverseTemplate:j,path:n,pathRoot:m,previousContext:l,isEscaped:!b.hash.unescaped,templateData:b.data});k.appendChild(p);var q=function(){Ember.run.once(p,"rerenderIfNeeded")};n!==""&&Ember.addObserver(m,n,q)}else h.buffer.push(d(m,n,b))};g.registerHelper("_triageMustache",function(a,b){return h[a]?h[a].call(this,b):h.bind.apply(this,arguments)}),g.registerHelper("bind",function(a,b){var c=b.contexts&&b.contexts[0]||this;return i.call(c,a,b,!1,function(a){return!Ember.none(a)})}),g.registerHelper("boundIf",function(b,c){var d=c.contexts&&c.contexts[0]||this,e=function(b){return Ember.typeOf(b)==="array"?a(b,"length")!==0:!!b};return i.call(d,b,c,!0,e,e)}),g.registerHelper("with",function(a,b){if(arguments.length===4){var c,d,f,g;b=arguments[3],c=arguments[2],d=arguments[0];if(Ember.isGlobalPath(d))Ember.bind(b.data.keywords,c,d);else{g=e(this,d,b.data),d=g.path,f=g.root;var j=Ember.$.expando+Ember.guidFor(f);b.data.keywords[j]=f;var k=d?j+"."+d:j;Ember.bind(b.data.keywords,c,k)}return i.call(this,d,b.fn,!0,function(a){return!Ember.none(a)})}return h.bind.call(b.contexts[0],a,b)}),g.registerHelper("if",function(a,b){return h.boundIf.call(b.contexts[0],a,b)}),g.registerHelper("unless",function(a,b){var c=b.fn,d=b.inverse;return b.fn=d,b.inverse=c,h.boundIf.call(b.contexts[0],a,b)}),g.registerHelper("bindAttr",function(a){var b=a.hash,c=a.data.view,h=[],i=this,j=++Ember.$.uuid,k=b["class"];if(k!==null&&k!==undefined){var l=g.bindClasses(this,k,c,j,a);h.push('class="'+Handlebars.Utils.escapeExpression(l.join(" "))+'"'),delete b["class"]}var m=Ember.keys(b);return f.call(m,function(f){var g=b[f],k,l;l=e(i,g,a.data),k=l.root,g=l.path;var m=g==="this"?k:d(k,g,a),n=Ember.typeOf(m),o,p;o=function(){var e=d(k,g,a),h=c.$("[data-bindattr-"+j+"='"+j+"']");if(h.length===0){Ember.removeObserver(k,g,p);return}Ember.View.applyAttributeBindings(h,f,e)},p=function(){Ember.run.once(o)},g!=="this"&&Ember.addObserver(k,g,p),n==="string"||n==="number"&&!isNaN(m)?h.push(f+'="'+Handlebars.Utils.escapeExpression(m)+'"'):m&&n==="boolean"&&h.push(f+'="'+f+'"')},this),h.push("data-bindattr-"+j+'="'+j+'"'),new g.SafeString(h.join(" "))}),g.bindClasses=function(a,b,c,g,h){var i=[],j,k,l,m=function(a,b,c,e){var f=b!==""?d(a,b,e):!0;if(!!f&&c)return c;if(f===!0){var g=b.split(".");return Ember.String.dasherize(g[g.length-1])}return f!==!1&&f!==undefined&&f!==null?f:null};return f.call(b.split(" "),function(b){var d,f,n,o=b.split(":"),p=o[0],q=o[1],r=a,s;p!==""&&(s=e(a,p,h.data),r=s.root,p=s.path),f=function(){j=m(r,p,q,h),l=g?c.$("[data-bindattr-"+g+"='"+g+"']"):c.$(),l.length===0?Ember.removeObserver(r,p,n):(d&&l.removeClass(d),j?(l.addClass(j),d=j):d=null)},n=function(){Ember.run.once(f)},p!==""&&Ember.addObserver(r,p,n),k=m(r,p,q,h),k&&(i.push(k),d=k)}),i}}(),function(){var a=Ember.get,b=Ember.set,c=/^parentView\./,d=Ember.Handlebars;d.ViewHelper=Ember.Object.create({propertiesFromHTMLOptions:function(a,b){var c=a.hash,d=a.data,e={},f=c["class"],g=!1;c.id&&(e.elementId=c.id,g=!0),f&&(f=f.split(" "),e.classNames=f,g=!0),c.classBinding&&(e.classNameBindings=c.classBinding.split(" "),g=!0),c.classNameBindings&&(e.classNameBindings=c.classNameBindings.split(" "),g=!0),c.attributeBindings&&(e.attributeBindings=null,g=!0),g&&(c=Ember.$.extend({},c),delete c.id,delete c["class"],delete c.classBinding);var h,i;for(var j in c){if(!c.hasOwnProperty(j))continue;Ember.IS_BINDING.test(j)&&typeof c[j]=="string"&&(h=c[j],i=Ember.Handlebars.normalizePath(null,h,d),i.isKeyword?c[j]="templateData.keywords."+h:Ember.isGlobalPath(h)||(h==="this"?c[j]="bindingContext":c[j]="bindingContext."+h))}return e.bindingContext=b,Ember.$.extend(c,e)},helper:function(a,b,c){var e=c.inverse,f=c.data,g=f.view,h=c.fn,i=c.hash,j;"string"==typeof b?j=d.getPath(a,b,c):j=b;var k=this.propertiesFromHTMLOptions(c,a),l=f.view;k.templateData=c.data,h&&(k.template=h),l.appendChild(j,k)}}),d.registerHelper("view",function(a,b){return a&&a.data&&a.data.isRenderData&&(b=a,a="Ember.View"),d.ViewHelper.helper(this,a,b)})}(),function(){var a=Ember.get,b=Ember.Handlebars.getPath,c=Ember.String.fmt;Ember.Handlebars.registerHelper("collection",function(c,d){c&&c.data&&c.data.isRenderData&&(d=c,c=undefined);var e=d.fn,f=d.data,g=d.inverse,h;h=c?b(this,c,d):Ember.CollectionView;var i=d.hash,j={},k,l,m=i.itemViewClass,n=h.proto();delete i.itemViewClass,l=m?b(n,m,d):n.itemViewClass;for(var o in i)i.hasOwnProperty(o)&&(k=o.match(/^item(.)(.*)$/),k&&(j[k[1].toLowerCase()+k[2]]=i[o],delete i[o]));var p=i.tagName||n.tagName;e&&(j.template=e,delete d.fn);var q;g&&g!==Handlebars.VM.noop?(q=a(n,"emptyViewClass"),q=q.extend({template:g,tagName:j.tagName})):i.emptyViewClass&&(q=b(this,i.emptyViewClass,d)),i.emptyView=q,i.eachHelper==="each"&&(j._context=Ember.computed(function(){return a(this,"content")}).property("content"),delete i.eachHelper);var r=Ember.Handlebars.ViewHelper.propertiesFromHTMLOptions({data:f,hash:j},this);return i.itemViewClass=l.extend(r),Ember.Handlebars.helpers.view.call(this,h,d)})}(),function(){var a=Ember.Handlebars.getPath;Ember.Handlebars.registerHelper("unbound",function(b,c){var d=c.contexts&&c.contexts[0]||this;return a(d,b,c)})}(),function(){var a=Ember.Handlebars.getPath,b=Ember.Handlebars.normalizePath;Ember.Handlebars.registerHelper("log",function(c,d){var e=d.contexts&&d.contexts[0]||this,f=b(e,c,d.data),g=f.root,h=f.path,i=h==="this"?g:a(g,h,d);Ember.Logger.log(i)}),Ember.Handlebars.registerHelper("debugger",function(){debugger})}(),function(){var a=Ember.get,b=Ember.set;Ember.Handlebars.EachView=Ember.CollectionView.extend(Ember._Metamorph,{itemViewClass:Ember._MetamorphView,emptyViewClass:Ember._MetamorphView,createChildView:function(c,d){c=this._super(c,d);var e=a(this,"keyword");if(e){var f=a(c,"templateData");f=Ember.copy(f),f.keywords=c.cloneKeywords(),b(c,"templateData",f);var g=a(c,"content");f.keywords[e]=g}return c}}),Ember.Handlebars.registerHelper("each",function(a,b){if(arguments.length===4){var c=arguments[0];b=arguments[3],a=arguments[2],a===""&&(a="this"),b.hash.keyword=c}else b.hash.eachHelper="each";return b.hash.contentBinding=a,Ember.Handlebars.helpers.collection.call(this,"Ember.Handlebars.EachView",b)})}(),function(){Ember.Handlebars.registerHelper("template",function(a,b){var c=Ember.TEMPLATES[a];Ember.TEMPLATES[a](this,{data:b.data})})}(),function(){var a=Ember.Handlebars,b=a.getPath,c=Ember.get,d=a.ActionHelper={registeredActions:{}};d.registerAction=function(a,b,c,e,f){var g=(++Ember.$.uuid).toString();return d.registeredActions[g]={eventName:b,handler:function(b){return b.view=e,b.context=f,c.isState&&typeof c.send=="function"?c.send(a,b):c[a].call(c,b)}},e.on("willRerender",function(){delete d.registeredActions[g]}),g},a.registerHelper("action",function(e,f){var g=f.hash,h=g.on||"click",i=f.data.view,j,k,l;i=c(i,"concreteView");if(g.target)j=b(this,g.target,f);else if(l=f.data.keywords.controller)j=c(l,"target");j=j||i,k=g.context?b(this,g.context,f):f.contexts[0];var m=[],n;g.href&&j.urlForEvent&&(n=j.urlForEvent(e,k),m.push('href="'+n+'"'));var o=d.registerAction(e,h,j,i,k);return m.push('data-ember-action="'+o+'"'),new a.SafeString(m.join(" "))})}(),function(){var a=Ember.get,b=Ember.set;Ember.Handlebars.registerHelper("yield",function(b){var c=b.data.view,d;while(c&&!a(c,"layout"))c=a(c,"parentView");d=a(c,"template"),d&&d(this,b)})}(),function(){Ember.Handlebars.registerHelper("outlet",function(a,b){return a&&a.data&&a.data.isRenderData&&(b=a,a="view"),b.hash.currentViewBinding="controller."+a,Ember.Handlebars.helpers.view.call(this,Ember.ContainerView,b)})}(),function(){}(),function(){}(),function(){var a=Ember.set,b=Ember.get;Ember.Checkbox=Ember.View.extend({classNames:["ember-checkbox"],tagName:"input",attributeBindings:["type","checked","disabled"],type:"checkbox",checked:!1,disabled:!1,init:function(){this._super(),this.on("change",this,this._updateElementValue)},_updateElementValue:function(){a(this,"checked",this.$().prop("checked"))}})}(),function(){var a=Ember.get,b=Ember.set;Ember.TextSupport=Ember.Mixin.create({value:"",attributeBindings:["placeholder","disabled","maxlength"],placeholder:null,disabled:!1,maxlength:null,insertNewline:Ember.K,cancel:Ember.K,init:function(){this._super(),this.on("focusOut",this,this._elementValueDidChange),this.on("change",this,this._elementValueDidChange),this.on("keyUp",this,this.interpretKeyEvents)},interpretKeyEvents:function(a){var b=Ember.TextSupport.KEY_EVENTS,c=b[a.keyCode];this._elementValueDidChange();if(c)return this[c](a)},_elementValueDidChange:function(){b(this,"value",this.$().val())}}),Ember.TextSupport.KEY_EVENTS={13:"insertNewline",27:"cancel"}}(),function(){var a=Ember.get,b=Ember.set;Ember.TextField=Ember.View.extend(Ember.TextSupport,{classNames:["ember-text-field"],tagName:"input",attributeBindings:["type","value","size"],value:"",type:"text",size:null})}(),function(){var a=Ember.get,b=Ember.set;Ember.Button=Ember.View.extend(Ember.TargetActionSupport,{classNames:["ember-button"],classNameBindings:["isActive"],tagName:"button",propagateEvents:!1,attributeBindings:["type","disabled","href"],targetObject:Ember.computed(function(){var b=a(this,"target"),c=a(this,"context"),d=a(this,"templateData");return typeof b!="string"?b:Ember.Handlebars.getPath(c,b,{data:d})}).property("target").cacheable(),type:Ember.computed(function(a,b){var c=this.get("tagName");b!==undefined&&(this._type=b);if(this._type!==undefined)return this._type;if(c==="input"||c==="button")return"button"}).property("tagName").cacheable(),disabled:!1,href:Ember.computed(function(){return this.get("tagName")==="a"?"#":null}).property("tagName").cacheable(),mouseDown:function(){return a(this,"disabled")||(b(this,"isActive",!0),this._mouseDown=!0,this._mouseEntered=!0),a(this,"propagateEvents")},mouseLeave:function(){this._mouseDown&&(b(this,"isActive",!1),this._mouseEntered=!1)},mouseEnter:function(){this._mouseDown&&(b(this,"isActive",!0),this._mouseEntered=!0)},mouseUp:function(c){return a(this,"isActive")&&(this.triggerAction(),b(this,"isActive",!1)),this._mouseDown=!1,this._mouseEntered=!1,a(this,"propagateEvents")},keyDown:function(a){(a.keyCode===13||a.keyCode===32)&&this.mouseDown()},keyUp:function(a){(a.keyCode===13||a.keyCode===32)&&this.mouseUp()},touchStart:function(a){return this.mouseDown(a)},touchEnd:function(a){return this.mouseUp(a)},init:function(){this._super()}})}(),function(){var a=Ember.get,b=Ember.set;Ember.TextArea=Ember.View.extend(Ember.TextSupport,{classNames:["ember-text-area"],tagName:"textarea",attributeBindings:["rows","cols"],rows:null,cols:null,_updateElementValue:Ember.observer(function(){this.$().val(a(this,"value"))},"value"),init:function( -){this._super(),this.on("didInsertElement",this,this._updateElementValue)}})}(),function(){Ember.TabContainerView=Ember.View.extend({init:function(){this._super()}})}(),function(){var a=Ember.get,b=Ember.getPath;Ember.TabPaneView=Ember.View.extend({tabsContainer:Ember.computed(function(){return this.nearestInstanceOf(Ember.TabContainerView)}).property().volatile(),isVisible:Ember.computed(function(){return a(this,"viewName")===b(this,"tabsContainer.currentView")}).property("tabsContainer.currentView").volatile(),init:function(){this._super()}})}(),function(){var a=Ember.get,b=Ember.setPath;Ember.TabView=Ember.View.extend({tabsContainer:Ember.computed(function(){return this.nearestInstanceOf(Ember.TabContainerView)}).property().volatile(),mouseUp:function(){b(this,"tabsContainer.currentView",a(this,"value"))},init:function(){this._super()}})}(),function(){}(),function(){var a=Ember.set,b=Ember.get,c=Ember.getPath,d=Ember.EnumerableUtils.indexOf,e=Ember.EnumerableUtils.indexesOf;Ember.Select=Ember.View.extend({tagName:"select",classNames:["ember-select"],defaultTemplate:Ember.Handlebars.template(function(b,c,d,e,f){function q(a,b){var c="",e,f,g,h;return b.buffer.push(""),c}function r(a,b){var c,e,f,g;c=a,e="Ember.SelectOption",f={},g="this",f.contentBinding=g,g=d.view||a.view,k={},k.hash=f,k.contexts=[],k.contexts.push(c),k.data=b,typeof g===m?c=g.call(a,e,k):g===o?c=n.call(a,"view",e,k):c=g,b.buffer.push(p(c))}d=d||Ember.Handlebars.helpers;var g="",h,i,j,k,l=this,m="function",n=d.helperMissing,o=void 0,p=this.escapeExpression;return h=c,i="view.prompt",j=d["if"],k=l.program(1,q,f),k.hash={},k.contexts=[],k.contexts.push(h),k.fn=k,k.inverse=l.noop,k.data=f,h=j.call(c,i,k),(h||h===0)&&f.buffer.push(h),h=c,i="view.content",j=d.each,k=l.program(3,r,f),k.hash={},k.contexts=[],k.contexts.push(h),k.fn=k,k.inverse=l.noop,k.data=f,h=j.call(c,i,k),(h||h===0)&&f.buffer.push(h),g}),attributeBindings:["multiple"],multiple:!1,content:null,selection:null,value:Ember.computed(function(a,d){if(arguments.length===2)return d;var e=b(this,"optionValuePath").replace(/^content\.?/,"");return e?c(this,"selection."+e):b(this,"selection")}).property("selection").cacheable(),prompt:null,optionLabelPath:"content",optionValuePath:"content",_change:function(){b(this,"multiple")?this._changeMultiple():this._changeSingle()},selectionDidChange:Ember.observer(function(){var c=b(this,"selection"),d=Ember.isArray(c);if(b(this,"multiple")){if(!d){a(this,"selection",Ember.A([c]));return}this._selectionDidChangeMultiple()}else this._selectionDidChangeSingle()},"selection"),valueDidChange:Ember.observer(function(){var a=b(this,"content"),d=b(this,"value"),e=b(this,"optionValuePath").replace(/^content\.?/,""),f=e?c(this,"selection."+e):b(this,"selection"),g;d!==f&&(g=a.find(function(a){return d===(e?b(a,e):a)}),this.set("selection",g))},"value"),_triggerChange:function(){var a=b(this,"selection");a&&this.selectionDidChange(),this._change()},_changeSingle:function(){var c=this.$()[0].selectedIndex,d=b(this,"content"),e=b(this,"prompt");if(!d)return;if(e&&c===0){a(this,"selection",null);return}e&&(c-=1),a(this,"selection",d.objectAt(c))},_changeMultiple:function(){var c=this.$("option:selected"),d=b(this,"prompt"),e=d?1:0,f=b(this,"content");if(!f)return;if(c){var g=c.map(function(){return this.index-e}).toArray();a(this,"selection",f.objectsAt(g))}},_selectionDidChangeSingle:function(){var a=this.$()[0],c=b(this,"content"),e=b(this,"selection"),f=c?d(c,e):-1,g=b(this,"prompt");g&&(f+=1),a&&(a.selectedIndex=f)},_selectionDidChangeMultiple:function(){var a=b(this,"content"),c=b(this,"selection"),f=a?e(a,c):[-1],g=b(this,"prompt"),h=g?1:0,i=this.$("option"),j;i&&i.each(function(){j=this.index>-1?this.index+h:-1,this.selected=d(f,j)>-1})},init:function(){this._super(),this.on("didInsertElement",this,this._triggerChange),this.on("change",this,this._change)}}),Ember.SelectOption=Ember.View.extend({tagName:"option",attributeBindings:["value","selected"],defaultTemplate:function(a,b){b={data:b.data,hash:{}},Ember.Handlebars.helpers.bind.call(a,"view.label",b)},init:function(){this.labelPathDidChange(),this.valuePathDidChange(),this._super()},selected:Ember.computed(function(){var a=b(this,"content"),e=c(this,"parentView.selection");return c(this,"parentView.multiple")?e&&d(e,a)>-1:a==e}).property("content","parentView.selection").volatile(),labelPathDidChange:Ember.observer(function(){var a=c(this,"parentView.optionLabelPath");if(!a)return;Ember.defineProperty(this,"label",Ember.computed(function(){return c(this,a)}).property(a).cacheable())},"parentView.optionLabelPath"),valuePathDidChange:Ember.observer(function(){var a=c(this,"parentView.optionValuePath");if(!a)return;Ember.defineProperty(this,"value",Ember.computed(function(){return c(this,a)}).property(a).cacheable())},"parentView.optionValuePath")})}(),function(){}(),function(){Ember.Handlebars.bootstrap=function(a){var b='script[type="text/x-handlebars"], script[type="text/x-raw-handlebars"]';Ember.ENV.LEGACY_HANDLEBARS_TAGS&&(b+=', script[type="text/html"]'),Ember.$(b,a).each(function(){var a=Ember.$(this),b=a.attr("type"),c=a.attr("type")==="text/x-raw-handlebars"?Ember.$.proxy(Handlebars.compile,Handlebars):Ember.$.proxy(Ember.Handlebars.compile,Ember.Handlebars),d=a.attr("data-template-name")||a.attr("id"),e=c(a.html()),f,g,h,i;if(d)Ember.TEMPLATES[d]=e,a.remove();else{if(a.parents("head").length!==0)throw new Ember.Error("Template found in without a name specified. Please provide a data-template-name attribute.\n"+a.html());g=a.attr("data-view"),f=g?Ember.getPath(g):Ember.View,h=a.attr("data-element-id"),i={template:e},h&&(i.elementId=h),f=f.create(i),f._insertElementLater(function(){a.replaceWith(this.$()),a=null})}})},Ember.$(document).ready(function(){Ember.Handlebars.bootstrap(Ember.$(document))})}(),function(){}(); diff --git a/dependency-examples/emberjs_require/js/lib/require/require.js b/dependency-examples/emberjs_require/js/lib/require/require.js deleted file mode 100644 index b6090d17a8..0000000000 --- a/dependency-examples/emberjs_require/js/lib/require/require.js +++ /dev/null @@ -1,31 +0,0 @@ -/* - RequireJS 1.0.2 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. - Available via the MIT or new BSD license. - see: http://github.com/jrburke/requirejs for details -*/ -var requirejs,require,define; -(function(){function J(a){return M.call(a)==="[object Function]"}function E(a){return M.call(a)==="[object Array]"}function Z(a,c,h){for(var k in c)if(!(k in K)&&(!(k in a)||h))a[k]=c[k];return d}function N(a,c,d){a=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+a);if(d)a.originalError=d;return a}function $(a,c,d){var k,j,q;for(k=0;q=c[k];k++){q=typeof q==="string"?{name:q}:q;j=q.location;if(d&&(!j||j.indexOf("/")!==0&&j.indexOf(":")===-1))j=d+"/"+(j||q.name);a[q.name]={name:q.name,location:j|| -q.name,main:(q.main||"main").replace(ea,"").replace(aa,"")}}}function V(a,c){a.holdReady?a.holdReady(c):c?a.readyWait+=1:a.ready(!0)}function fa(a){function c(b,l){var f,a;if(b&&b.charAt(0)===".")if(l){p.pkgs[l]?l=[l]:(l=l.split("/"),l=l.slice(0,l.length-1));f=b=l.concat(b.split("/"));var c;for(a=0;c=f[a];a++)if(c===".")f.splice(a,1),a-=1;else if(c==="..")if(a===1&&(f[2]===".."||f[0]===".."))break;else a>0&&(f.splice(a-1,2),a-=2);a=p.pkgs[f=b[0]];b=b.join("/");a&&b===f+"/"+a.main&&(b=f)}else b.indexOf("./")=== -0&&(b=b.substring(2));return b}function h(b,l){var f=b?b.indexOf("!"):-1,a=null,d=l?l.name:null,i=b,e,h;f!==-1&&(a=b.substring(0,f),b=b.substring(f+1,b.length));a&&(a=c(a,d));b&&(a?e=(f=m[a])&&f.normalize?f.normalize(b,function(b){return c(b,d)}):c(b,d):(e=c(b,d),h=E[e],h||(h=g.nameToUrl(e,null,l),E[e]=h)));return{prefix:a,name:e,parentMap:l,url:h,originalName:i,fullName:a?a+"!"+(e||""):e}}function k(){var b=!0,l=p.priorityWait,f,a;if(l){for(a=0;f=l[a];a++)if(!s[f]){b=!1;break}b&&delete p.priorityWait}return b} -function j(b,l,f){return function(){var a=ga.call(arguments,0),c;if(f&&J(c=a[a.length-1]))c.__requireJsBuild=!0;a.push(l);return b.apply(null,a)}}function q(b,l){var a=j(g.require,b,l);Z(a,{nameToUrl:j(g.nameToUrl,b),toUrl:j(g.toUrl,b),defined:j(g.requireDefined,b),specified:j(g.requireSpecified,b),isBrowser:d.isBrowser});return a}function o(b){var l,a,c,C=b.callback,i=b.map,e=i.fullName,ba=b.deps;c=b.listeners;if(C&&J(C)){if(p.catchError.define)try{a=d.execCb(e,b.callback,ba,m[e])}catch(k){l=k}else a= -d.execCb(e,b.callback,ba,m[e]);if(e)(C=b.cjsModule)&&C.exports!==void 0&&C.exports!==m[e]?a=m[e]=b.cjsModule.exports:a===void 0&&b.usingExports?a=m[e]:(m[e]=a,F[e]&&(Q[e]=!0))}else e&&(a=m[e]=C,F[e]&&(Q[e]=!0));if(D[b.id])delete D[b.id],b.isDone=!0,g.waitCount-=1,g.waitCount===0&&(I=[]);delete R[e];if(d.onResourceLoad&&!b.placeholder)d.onResourceLoad(g,i,b.depArray);if(l)return a=(e?h(e).url:"")||l.fileName||l.sourceURL,c=l.moduleTree,l=N("defineerror",'Error evaluating module "'+e+'" at location "'+ -a+'":\n'+l+"\nfileName:"+a+"\nlineNumber: "+(l.lineNumber||l.line),l),l.moduleName=e,l.moduleTree=c,d.onError(l);for(l=0;C=c[l];l++)C(a)}function r(b,a){return function(f){b.depDone[a]||(b.depDone[a]=!0,b.deps[a]=f,b.depCount-=1,b.depCount||o(b))}}function u(b,a){var f=a.map,c=f.fullName,h=f.name,i=L[b]||(L[b]=m[b]),e;if(!a.loading)a.loading=!0,e=function(b){a.callback=function(){return b};o(a);s[a.id]=!0;w()},e.fromText=function(b,a){var l=O;s[b]=!1;g.scriptCount+=1;g.fake[b]=!0;l&&(O=!1);d.exec(a); -l&&(O=!0);g.completeLoad(b)},c in m?e(m[c]):i.load(h,q(f.parentMap,!0),e,p)}function v(b){D[b.id]||(D[b.id]=b,I.push(b),g.waitCount+=1)}function B(b){this.listeners.push(b)}function t(b,a){var f=b.fullName,c=b.prefix,d=c?L[c]||(L[c]=m[c]):null,i,e;f&&(i=R[f]);if(!i&&(e=!0,i={id:(c&&!d?M++ +"__p@:":"")+(f||"__r@"+M++),map:b,depCount:0,depDone:[],depCallbacks:[],deps:[],listeners:[],add:B},y[i.id]=!0,f&&(!c||L[c])))R[f]=i;c&&!d?(f=t(h(c),!0),f.add(function(){var a=h(b.originalName,b.parentMap),a=t(a, -!0);i.placeholder=!0;a.add(function(b){i.callback=function(){return b};o(i)})})):e&&a&&(s[i.id]=!1,g.paused.push(i),v(i));return i}function x(b,a,f,c){var b=h(b,c),d=b.name,i=b.fullName,e=t(b),k=e.id,j=e.deps,n;if(i){if(i in m||s[k]===!0||i==="jquery"&&p.jQuery&&p.jQuery!==f().fn.jquery)return;y[k]=!0;s[k]=!0;i==="jquery"&&f&&S(f())}e.depArray=a;e.callback=f;for(f=0;f0)){if(p.priorityWait)if(k())w();else return;for(j in s)if(!(j in K)&&(c=!0,!s[j]))if(a)b+=j+" ";else{h=!0;break}if(c||g.waitCount){if(a&&b)return j=N("timeout","Load timeout for modules: "+b),j.requireType="timeout",j.requireModules=b,d.onError(j);if(h||g.scriptCount){if((G||ca)&&!W)W=setTimeout(function(){W=0;A()},50)}else{if(g.waitCount){for(H= -0;b=I[H];H++)z(b,{});g.paused.length&&w();X<5&&(X+=1,A())}X=0;d.checkReadyState()}}}}var g,w,p={waitSeconds:7,baseUrl:"./",paths:{},pkgs:{},catchError:{}},P=[],y={require:!0,exports:!0,module:!0},E={},m={},s={},D={},I=[],T={},M=0,R={},L={},F={},Q={},Y=0;S=function(b){if(!g.jQuery&&(b=b||(typeof jQuery!=="undefined"?jQuery:null))&&!(p.jQuery&&b.fn.jquery!==p.jQuery)&&("holdReady"in b||"readyWait"in b))if(g.jQuery=b,n(["jquery",[],function(){return jQuery}]),g.scriptCount)V(b,!0),g.jQueryIncremented= -!0};w=function(){var b,a,c,h,j,i;Y+=1;if(g.scriptCount<=0)g.scriptCount=0;for(;P.length;)if(b=P.shift(),b[0]===null)return d.onError(N("mismatch","Mismatched anonymous define() module: "+b[b.length-1]));else n(b);if(!p.priorityWait||k())for(;g.paused.length;){j=g.paused;g.pausedCount+=j.length;g.paused=[];for(h=0;b=j[h];h++)a=b.map,c=a.url,i=a.fullName,a.prefix?u(a.prefix,b):!T[c]&&!s[i]&&(d.load(g,i,c),c.indexOf("empty:")!==0&&(T[c]=!0));g.startTime=(new Date).getTime();g.pausedCount-=j.length}Y=== -1&&A();Y-=1};g={contextName:a,config:p,defQueue:P,waiting:D,waitCount:0,specified:y,loaded:s,urlMap:E,urlFetched:T,scriptCount:0,defined:m,paused:[],pausedCount:0,plugins:L,needFullExec:F,fake:{},fullExec:Q,managerCallbacks:R,makeModuleMap:h,normalize:c,configure:function(b){var a,c,d;b.baseUrl&&b.baseUrl.charAt(b.baseUrl.length-1)!=="/"&&(b.baseUrl+="/");a=p.paths;d=p.pkgs;Z(p,b,!0);if(b.paths){for(c in b.paths)c in K||(a[c]=b.paths[c]);p.paths=a}if((a=b.packagePaths)||b.packages){if(a)for(c in a)c in -K||$(d,a[c],c);b.packages&&$(d,b.packages);p.pkgs=d}if(b.priority)c=g.requireWait,g.requireWait=!1,g.takeGlobalQueue(),w(),g.require(b.priority),w(),g.requireWait=c,p.priorityWait=b.priority;if(b.deps||b.callback)g.require(b.deps||[],b.callback)},requireDefined:function(b,a){return h(b,a).fullName in m},requireSpecified:function(b,a){return h(b,a).fullName in y},require:function(b,c,f){if(typeof b==="string"){if(J(c))return d.onError(N("requireargs","Invalid require call"));if(d.get)return d.get(g, -b,c);c=h(b,c);b=c.fullName;return!(b in m)?d.onError(N("notloaded","Module name '"+c.fullName+"' has not been loaded yet for context: "+a)):m[b]}(b&&b.length||c)&&x(null,b,c,f);if(!g.requireWait)for(;!g.scriptCount&&g.paused.length;)g.takeGlobalQueue(),w();return g.require},takeGlobalQueue:function(){U.length&&(ha.apply(g.defQueue,[g.defQueue.length-1,0].concat(U)),U=[])},completeLoad:function(b){var a;for(g.takeGlobalQueue();P.length;)if(a=P.shift(),a[0]===null){a[0]=b;break}else if(a[0]===b)break; -else n(a),a=null;a?n(a):n([b,[],b==="jquery"&&typeof jQuery!=="undefined"?function(){return jQuery}:null]);S();d.isAsync&&(g.scriptCount-=1);w();d.isAsync||(g.scriptCount-=1)},toUrl:function(a,c){var d=a.lastIndexOf("."),h=null;d!==-1&&(h=a.substring(d,a.length),a=a.substring(0,d));return g.nameToUrl(a,h,c)},nameToUrl:function(a,h,f){var j,k,i,e,m=g.config,a=c(a,f&&f.fullName);if(d.jsExtRegExp.test(a))h=a+(h?h:"");else{j=m.paths;k=m.pkgs;f=a.split("/");for(e=f.length;e>0;e--)if(i=f.slice(0,e).join("/"), -j[i]){f.splice(0,e,j[i]);break}else if(i=k[i]){a=a===i.name?i.location+"/"+i.main:i.location;f.splice(0,e,a);break}h=f.join("/")+(h||".js");h=(h.charAt(0)==="/"||h.match(/^\w+:/)?"":m.baseUrl)+h}return m.urlArgs?h+((h.indexOf("?")===-1?"?":"&")+m.urlArgs):h}};g.jQueryCheck=S;g.resume=w;return g}function ia(){var a,c,d;if(n&&n.readyState==="interactive")return n;a=document.getElementsByTagName("script");for(c=a.length-1;c>-1&&(d=a[c]);c--)if(d.readyState==="interactive")return n=d;return null}var ja= -/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,ka=/require\(\s*["']([^'"\s]+)["']\s*\)/g,ea=/^\.\//,aa=/\.js$/,M=Object.prototype.toString,r=Array.prototype,ga=r.slice,ha=r.splice,G=!!(typeof window!=="undefined"&&navigator&&document),ca=!G&&typeof importScripts!=="undefined",la=G&&navigator.platform==="PLAYSTATION 3"?/^complete$/:/^(complete|loaded)$/,da=typeof opera!=="undefined"&&opera.toString()==="[object Opera]",K={},t={},U=[],n=null,X=0,O=!1,d,r={},I,v,x,y,u,z,A,H,B,S,W;if(typeof define==="undefined"){if(typeof requirejs!== -"undefined")if(J(requirejs))return;else r=requirejs,requirejs=void 0;typeof require!=="undefined"&&!J(require)&&(r=require,require=void 0);d=requirejs=function(a,c,d){var k="_",j;!E(a)&&typeof a!=="string"&&(j=a,E(c)?(a=c,c=d):a=[]);if(j&&j.context)k=j.context;d=t[k]||(t[k]=fa(k));j&&d.configure(j);return d.require(a,c)};d.config=function(a){return d(a)};require||(require=d);d.toUrl=function(a){return t._.toUrl(a)};d.version="1.0.2";d.jsExtRegExp=/^\/|:|\?|\.js$/;v=d.s={contexts:t,skipAsync:{}};if(d.isAsync= -d.isBrowser=G)if(x=v.head=document.getElementsByTagName("head")[0],y=document.getElementsByTagName("base")[0])x=v.head=y.parentNode;d.onError=function(a){throw a;};d.load=function(a,c,h){d.resourcesReady(!1);a.scriptCount+=1;d.attach(h,a,c);if(a.jQuery&&!a.jQueryIncremented)V(a.jQuery,!0),a.jQueryIncremented=!0};define=function(a,c,d){var k,j;typeof a!=="string"&&(d=c,c=a,a=null);E(c)||(d=c,c=[]);!c.length&&J(d)&&d.length&&(d.toString().replace(ja,"").replace(ka,function(a,d){c.push(d)}),c=(d.length=== -1?["require"]:["require","exports","module"]).concat(c));if(O&&(k=I||ia()))a||(a=k.getAttribute("data-requiremodule")),j=t[k.getAttribute("data-requirecontext")];(j?j.defQueue:U).push([a,c,d])};define.amd={multiversion:!0,plugins:!0,jQuery:!0};d.exec=function(a){return eval(a)};d.execCb=function(a,c,d,k){return c.apply(k,d)};d.addScriptToDom=function(a){I=a;y?x.insertBefore(a,y):x.appendChild(a);I=null};d.onScriptLoad=function(a){var c=a.currentTarget||a.srcElement,h;if(a.type==="load"||c&&la.test(c.readyState))n= -null,a=c.getAttribute("data-requirecontext"),h=c.getAttribute("data-requiremodule"),t[a].completeLoad(h),c.detachEvent&&!da?c.detachEvent("onreadystatechange",d.onScriptLoad):c.removeEventListener("load",d.onScriptLoad,!1)};d.attach=function(a,c,h,k,j,n){var o;if(G)return k=k||d.onScriptLoad,o=c&&c.config&&c.config.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script"),o.type=j||"text/javascript",o.charset="utf-8",o.async=!v.skipAsync[a],c&&o.setAttribute("data-requirecontext", -c.contextName),o.setAttribute("data-requiremodule",h),o.attachEvent&&!da?(O=!0,n?o.onreadystatechange=function(){if(o.readyState==="loaded")o.onreadystatechange=null,o.attachEvent("onreadystatechange",k),n(o)}:o.attachEvent("onreadystatechange",k)):o.addEventListener("load",k,!1),o.src=a,n||d.addScriptToDom(o),o;else ca&&(importScripts(a),c.completeLoad(h));return null};if(G){u=document.getElementsByTagName("script");for(H=u.length-1;H>-1&&(z=u[H]);H--){if(!x)x=z.parentNode;if(A=z.getAttribute("data-main")){if(!r.baseUrl)u= -A.split("/"),z=u.pop(),u=u.length?u.join("/")+"/":"./",r.baseUrl=u,A=z.replace(aa,"");r.deps=r.deps?r.deps.concat(A):[A];break}}}d.checkReadyState=function(){var a=v.contexts,c;for(c in a)if(!(c in K)&&a[c].waitCount)return;d.resourcesReady(!0)};d.resourcesReady=function(a){var c,h;d.resourcesDone=a;if(d.resourcesDone)for(h in a=v.contexts,a)if(!(h in K)&&(c=a[h],c.jQueryIncremented))V(c.jQuery,!1),c.jQueryIncremented=!1};d.pageLoaded=function(){if(document.readyState!=="complete")document.readyState= -"complete"};if(G&&document.addEventListener&&!document.readyState)document.readyState="loading",window.addEventListener("load",d.pageLoaded,!1);d(r);if(d.isAsync&&typeof setTimeout!=="undefined")B=v.contexts[r.context||"_"],B.requireWait=!0,setTimeout(function(){B.requireWait=!1;B.takeGlobalQueue();B.jQueryCheck();B.scriptCount||B.resume();d.checkReadyState()},0)}})(); diff --git a/dependency-examples/emberjs_require/js/lib/require/text.js b/dependency-examples/emberjs_require/js/lib/require/text.js deleted file mode 100644 index 0caaacf2c9..0000000000 --- a/dependency-examples/emberjs_require/js/lib/require/text.js +++ /dev/null @@ -1,11 +0,0 @@ -/* - RequireJS text 0.27.0 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. - Available via the MIT or new BSD license. - see: http://github.com/jrburke/requirejs for details -*/ -(function(){var k=["Msxml2.XMLHTTP","Microsoft.XMLHTTP","Msxml2.XMLHTTP.4.0"],n=/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,o=/]*>\s*([\s\S]+)\s*<\/body>/im,i=typeof location!=="undefined"&&location.href,p=i&&location.protocol&&location.protocol.replace(/\:/,""),q=i&&location.hostname,r=i&&(location.port||void 0),j=[];define(function(){var g,h,l;typeof window!=="undefined"&&window.navigator&&window.document?h=function(a,b){var c=g.createXhr();c.open("GET",a,!0);c.onreadystatechange= -function(){c.readyState===4&&b(c.responseText)};c.send(null)}:typeof process!=="undefined"&&process.versions&&process.versions.node?(l=require.nodeRequire("fs"),h=function(a,b){b(l.readFileSync(a,"utf8"))}):typeof Packages!=="undefined"&&(h=function(a,b){var c=new java.io.File(a),e=java.lang.System.getProperty("line.separator"),c=new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(c),"utf-8")),d,f,g="";try{d=new java.lang.StringBuffer;(f=c.readLine())&&f.length()&& -f.charAt(0)===65279&&(f=f.substring(1));for(d.append(f);(f=c.readLine())!==null;)d.append(e),d.append(f);g=String(d.toString())}finally{c.close()}b(g)});return g={version:"0.27.0",strip:function(a){if(a){var a=a.replace(n,""),b=a.match(o);b&&(a=b[1])}else a="";return a},jsEscape:function(a){return a.replace(/(['\\])/g,"\\$1").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\r]/g,"\\r")},createXhr:function(){var a,b,c;if(typeof XMLHttpRequest!== -"undefined")return new XMLHttpRequest;else for(b=0;b<3;b++){c=k[b];try{a=new ActiveXObject(c)}catch(e){}if(a){k=[c];break}}if(!a)throw Error("createXhr(): XMLHttpRequest not available");return a},get:h,parseName:function(a){var b=!1,c=a.indexOf("."),e=a.substring(0,c),a=a.substring(c+1,a.length),c=a.indexOf("!");c!==-1&&(b=a.substring(c+1,a.length),b=b==="strip",a=a.substring(0,c));return{moduleName:e,ext:a,strip:b}},xdRegExp:/^((\w+)\:)?\/\/([^\/\\]+)/,useXhr:function(a,b,c,e){var d=g.xdRegExp.exec(a), -f;if(!d)return!0;a=d[2];d=d[3];d=d.split(":");f=d[1];d=d[0];return(!a||a===b)&&(!d||d===c)&&(!f&&!d||f===e)},finishLoad:function(a,b,c,e,d){c=b?g.strip(c):c;d.isBuild&&d.inlineText&&(j[a]=c);e(c)},load:function(a,b,c,e){var d=g.parseName(a),f=d.moduleName+"."+d.ext,m=b.toUrl(f),h=e&&e.text&&e.text.useXhr||g.useXhr;!i||h(m,p,q,r)?g.get(m,function(b){g.finishLoad(a,d.strip,b,c,e)}):b([f],function(a){g.finishLoad(d.moduleName+"."+d.ext,d.strip,a,c,e)})},write:function(a,b,c){if(b in j){var e=g.jsEscape(j[b]); -c.asModule(a+"!"+b,"define(function () { return '"+e+"';});\n")}},writeFile:function(a,b,c,e,d){var b=g.parseName(b),f=b.moduleName+"."+b.ext,h=c.toUrl(b.moduleName+"."+b.ext)+".js";g.load(f,c,function(){var b=function(a){return e(h,a)};b.asModule=function(a,b){return e.asModule(a,h,b)};g.write(a,f,b,d)},d)}}})})(); diff --git a/dependency-examples/emberjs_require/readme.md b/dependency-examples/emberjs_require/readme.md index a2aaabb05b..439eb5ddaa 100644 --- a/dependency-examples/emberjs_require/readme.md +++ b/dependency-examples/emberjs_require/readme.md @@ -1,13 +1,13 @@ -# Ember.js + Require.js • [TodoMVC](http://todomvc.com) +# Ember.js & RequireJS TodoMVC Example +This example was removed, because the Ember.js dependency injection architecture +does not provide appropriate hooks for asynchronous module loading yet and thus +the use of RequireJS with Ember.js is not advised. -## Running tests +To see what a TodoMVC application using Ember.js and RequireJS would look like +in its current state, visit: -To fire specs runner, append `#specs` to the url in address bar, and reload the webpage. +[Ember.js + RequireJS Source](https://github.com/stephenplusplus/todomvc/tree/emberjs_require/dependency-examples/emberjs_require) +[Ember.js + RequireJS Demo](http://stephenplusplus.github.io/todomvc-emberjs-requirejs/dependency-examples/emberjs_require) - -## Credit - -Initial release by @tomdale. - -Refactoring and maintenance by @stas. +For more information, [read the discussion](https://github.com/tastejs/todomvc/pull/528). diff --git a/dependency-examples/flight/app/js/app.js b/dependency-examples/flight/app/js/app.js index 8adf5b2d5d..e3ed21d75a 100644 --- a/dependency-examples/flight/app/js/app.js +++ b/dependency-examples/flight/app/js/app.js @@ -1,38 +1,26 @@ /*global define */ 'use strict'; -define( - [ - './data/todos', - './data/stats', - './ui/new_item', - './ui/todo_list', - './ui/stats', - './ui/main_selector', - './ui/toggle_all' - ], +define([ + './data/todos', + './data/stats', + './ui/new_item', + './ui/todo_list', + './ui/stats', + './ui/main_selector', + './ui/toggle_all' +], function (TodosData, StatsData, NewItemUI, TodoListUI, StatsUI, MainSelectorUI, ToggleAllUI) { + var initialize = function () { + StatsData.attachTo(document); + TodosData.attachTo(document); + NewItemUI.attachTo('#new-todo'); + MainSelectorUI.attachTo('#main'); + StatsUI.attachTo('#footer'); + ToggleAllUI.attachTo('#toggle-all'); + TodoListUI.attachTo('#todo-list'); + }; - function ( - TodosData, - StatsData, - NewItemUI, - TodoListUI, - StatsUI, - MainSelectorUI, - ToggleAllUI) { - - var initialize = function () { - StatsData.attachTo(document); - TodosData.attachTo(document); - NewItemUI.attachTo('#new-todo'); - MainSelectorUI.attachTo('#main'); - StatsUI.attachTo('#footer'); - ToggleAllUI.attachTo('#toggle-all'); - TodoListUI.attachTo('#todo-list'); - }; - - return { - initialize: initialize - }; - } -); + return { + initialize: initialize + }; +}); diff --git a/dependency-examples/flight/app/js/data/stats.js b/dependency-examples/flight/app/js/data/stats.js index f2fa4c19f0..129367cb45 100644 --- a/dependency-examples/flight/app/js/data/stats.js +++ b/dependency-examples/flight/app/js/data/stats.js @@ -1,39 +1,35 @@ /*global define */ 'use strict'; -define( - [ - 'flight/component', - '../store' - ], +define([ + 'flight/component', + '../store' +], function (defineComponent, dataStore) { + function stats() { + this.recount = function () { + var todos = dataStore.all(); + var all = todos.length; + var remaining = todos.reduce(function (memo, each) { + return memo += each.completed ? 0 : 1; + }, 0); - function (defineComponent, dataStore) { - return defineComponent(stats); + this.trigger('dataStatsCounted', { + all: all, + remaining: remaining, + completed: all - remaining, + filter: localStorage.getItem('filter') || '' + }); + }; - function stats() { - this.recount = function () { - var todos = dataStore.all(); - var all = todos.length; - var remaining = todos.reduce(function (memo, each) { - return memo += each.completed ? 0 : 1; - }, 0); + this.after('initialize', function () { + this.on(document, 'dataTodosLoaded', this.recount); + this.on(document, 'dataTodoAdded', this.recount); + this.on(document, 'dataTodoRemoved', this.recount); + this.on(document, 'dataTodoToggled', this.recount); + this.on(document, 'dataClearedCompleted', this.recount); + this.on(document, 'dataTodoToggledAll', this.recount); + }); + } - this.trigger('dataStatsCounted', { - all: all, - remaining: remaining, - completed: all - remaining, - filter: localStorage.getItem('filter') || '' - }); - }; - - this.after('initialize', function () { - this.on(document, 'dataTodosLoaded', this.recount); - this.on(document, 'dataTodoAdded', this.recount); - this.on(document, 'dataTodoRemoved', this.recount); - this.on(document, 'dataTodoToggled', this.recount); - this.on(document, 'dataClearedCompleted', this.recount); - this.on(document, 'dataTodoToggledAll', this.recount); - }); - } - } -); + return defineComponent(stats); +}); diff --git a/dependency-examples/flight/app/js/data/todos.js b/dependency-examples/flight/app/js/data/todos.js index 8eb7e2ad2f..5daf4d417f 100644 --- a/dependency-examples/flight/app/js/data/todos.js +++ b/dependency-examples/flight/app/js/data/todos.js @@ -1,105 +1,99 @@ /*global define */ 'use strict'; -define( - [ - 'flight/component', - '../store' - ], - - function (defineComponent, dataStore) { - return defineComponent(todos); - - function todos() { - var filter; - - this.add = function (e, data) { - var todo = dataStore.save({ - title: data.title, - completed: false - }); - - this.trigger('dataTodoAdded', { todo: todo, filter: filter }); - }; - - this.remove = function (e, data) { - var todo = dataStore.destroy(data.id); - - this.trigger('dataTodoRemoved', todo); - }; +define([ + 'flight/component', + '../store' +], function (defineComponent, dataStore) { + function todos() { + var filter; + + this.add = function (e, data) { + var todo = dataStore.save({ + title: data.title, + completed: false + }); - this.load = function (e, data) { - var todos; + this.trigger('dataTodoAdded', { todo: todo, filter: filter }); + }; - filter = localStorage.getItem('filter'); - todos = this.find(); - this.trigger('dataTodosLoaded', { todos: todos }); - }; + this.remove = function (e, data) { + var todo = dataStore.destroy(data.id); - this.update = function (e, data) { - dataStore.save(data); - }; + this.trigger('dataTodoRemoved', todo); + }; - this.toggleCompleted = function (e, data) { - var eventType; - var todo = dataStore.get(data.id); + this.load = function () { + var todos; - todo.completed = !todo.completed; - dataStore.save(todo); + filter = localStorage.getItem('filter'); + todos = this.find(); + this.trigger('dataTodosLoaded', { todos: todos }); + }; - eventType = filter ? 'dataTodoRemoved' : 'dataTodoToggled'; + this.update = function (e, data) { + dataStore.save(data); + }; - this.trigger(eventType, todo); - }; + this.toggleCompleted = function (e, data) { + var eventType; + var todo = dataStore.get(data.id); - this.toggleAllCompleted = function (e, data) { - dataStore.updateAll({ completed: data.completed }); - this.trigger('dataTodoToggledAll', { todos: this.find(filter) }); - }; + todo.completed = !todo.completed; + dataStore.save(todo); - this.filter = function (e, data) { - var todos; + eventType = filter ? 'dataTodoRemoved' : 'dataTodoToggled'; - localStorage.setItem('filter', data.filter); - filter = data.filter; - todos = this.find(); + this.trigger(eventType, todo); + }; - this.trigger('dataTodosFiltered', { todos: todos }); - }; + this.toggleAllCompleted = function (e, data) { + dataStore.updateAll({ completed: data.completed }); + this.trigger('dataTodoToggledAll', { todos: this.find(filter) }); + }; - this.find = function () { - var todos; + this.filter = function (e, data) { + var todos; - if (filter) { - todos = dataStore.find(function (each) { - return (typeof each[filter] !== 'undefined') ? each.completed : !each.completed; - }); - } - else { - todos = dataStore.all(); - } + localStorage.setItem('filter', data.filter); + filter = data.filter; + todos = this.find(); - return todos; - }; + this.trigger('dataTodosFiltered', { todos: todos }); + }; - this.clearCompleted = function () { - var todos; + this.find = function () { + var todos; - dataStore.destroyAll({ completed: true }); + if (filter) { + todos = dataStore.find(function (each) { + return (typeof each[filter] !== 'undefined') ? each.completed : !each.completed; + }); + } else { todos = dataStore.all(); - this.trigger('dataClearedCompleted', { todos: todos }); - }; - - this.after('initialize', function () { - this.on(document, 'uiAddRequested', this.add); - this.on(document, 'uiUpdateRequested', this.update); - this.on(document, 'uiRemoveRequested', this.remove); - this.on(document, 'uiLoadRequested', this.load); - this.on(document, 'uiToggleRequested', this.toggleCompleted); - this.on(document, 'uiToggleAllRequested', this.toggleAllCompleted); - this.on(document, 'uiClearRequested', this.clearCompleted); - this.on(document, 'uiFilterRequested', this.filter); - }); - } + } + + return todos; + }; + + this.clearCompleted = function () { + dataStore.destroyAll({ completed: true }); + + this.trigger('uiFilterRequested', { filter: filter }); + this.trigger('dataClearedCompleted'); + }; + + this.after('initialize', function () { + this.on(document, 'uiAddRequested', this.add); + this.on(document, 'uiUpdateRequested', this.update); + this.on(document, 'uiRemoveRequested', this.remove); + this.on(document, 'uiLoadRequested', this.load); + this.on(document, 'uiToggleRequested', this.toggleCompleted); + this.on(document, 'uiToggleAllRequested', this.toggleAllCompleted); + this.on(document, 'uiClearRequested', this.clearCompleted); + this.on(document, 'uiFilterRequested', this.filter); + }); } -); + + return defineComponent(todos); +}); diff --git a/dependency-examples/flight/app/js/store.js b/dependency-examples/flight/app/js/store.js index 20a93c2f6f..e9ab55ddae 100644 --- a/dependency-examples/flight/app/js/store.js +++ b/dependency-examples/flight/app/js/store.js @@ -1,11 +1,9 @@ -'use strict'; +/*global define */ -define( - [ - 'depot' - ], +'use strict'; - function (depot) { - return depot('todos', { idAttribute: 'id' }); - } -); +define([ + 'depot' +], function (depot) { + return depot('todos', { idAttribute: 'id' }); +}); diff --git a/dependency-examples/flight/app/js/ui/main_selector.js b/dependency-examples/flight/app/js/ui/main_selector.js index 6fd71b62c8..fd8d7927c9 100644 --- a/dependency-examples/flight/app/js/ui/main_selector.js +++ b/dependency-examples/flight/app/js/ui/main_selector.js @@ -1,24 +1,20 @@ /*global define */ 'use strict'; -define( - [ - 'flight/component' - ], +define([ + 'flight/component' +], function (defineComponent) { + function mainSelector() { + this.toggle = function (e, data) { + var toggle = data.all > 0; + this.$node.toggle(toggle); + }; - function (defineComponent) { - return defineComponent(mainSelector); - - function mainSelector() { - this.toggle = function (e, data) { - var toggle = data.all > 0; - this.$node.toggle(toggle); - }; - - this.after('initialize', function () { - this.$node.hide(); - this.on(document, 'dataStatsCounted', this.toggle); - }); - } + this.after('initialize', function () { + this.$node.hide(); + this.on(document, 'dataStatsCounted', this.toggle); + }); } -); + + return defineComponent(mainSelector); +}); diff --git a/dependency-examples/flight/app/js/ui/new_item.js b/dependency-examples/flight/app/js/ui/new_item.js index f4b71d7028..a86bb55ba5 100644 --- a/dependency-examples/flight/app/js/ui/new_item.js +++ b/dependency-examples/flight/app/js/ui/new_item.js @@ -1,33 +1,29 @@ /*global define */ 'use strict'; -define( - [ - 'flight/component' - ], +define([ + 'flight/component' +], function (defineComponent) { + function newItem() { + var ENTER_KEY = 13; - function (defineComponent) { - return defineComponent(newItem); + this.createOnEnter = function (e) { + if (e.which !== ENTER_KEY || + !this.$node.val().trim()) { + return; + } - function newItem() { - var ENTER_KEY = 13; - - this.createOnEnter = function (e) { - if (e.which !== ENTER_KEY || - !this.$node.val().trim()) { - return; - } - - this.trigger('uiAddRequested', { - title: this.$node.val().trim() - }); + this.trigger('uiAddRequested', { + title: this.$node.val().trim() + }); - this.$node.val(''); - }; + this.$node.val(''); + }; - this.after('initialize', function () { - this.on('keydown', this.createOnEnter); - }); - } + this.after('initialize', function () { + this.on('keydown', this.createOnEnter); + }); } -); + + return defineComponent(newItem); +}); diff --git a/dependency-examples/flight/app/js/ui/stats.js b/dependency-examples/flight/app/js/ui/stats.js index 9a91706ec7..e11db2c025 100644 --- a/dependency-examples/flight/app/js/ui/stats.js +++ b/dependency-examples/flight/app/js/ui/stats.js @@ -1,41 +1,37 @@ /*global define */ 'use strict'; -define( - [ - 'flight/component', - './with_filters', - 'text!app/templates/stats.html', - '../utils' - ], - - function (defineComponent, withFilters, statsTmpl, utils) { - return defineComponent(stats, withFilters); - - function stats() { - var template = utils.tmpl(statsTmpl); - - this.defaultAttrs({ - clearCompletedSelector: '#clear-completed' - }); - - this.render = function (e, data) { - var toggle = data.all > 0; - - this.$node.html(template(data)); - this.$node.toggle(toggle); - this.markSelected(data.filter); - }; - - this.clearCompleted = function (e, data) { - this.trigger('uiClearRequested'); - }; - - this.after('initialize', function () { - this.$node.hide(); - this.on(document, 'dataStatsCounted', this.render); - this.on('click', { 'clearCompletedSelector': this.clearCompleted }); - }); - } +define([ + 'flight/component', + './with_filters', + 'text!app/templates/stats.html', + '../utils' +], function (defineComponent, withFilters, statsTmpl, utils) { + function stats() { + var template = utils.tmpl(statsTmpl); + + this.defaultAttrs({ + clearCompletedSelector: '#clear-completed' + }); + + this.render = function (e, data) { + var toggle = data.all > 0; + + this.$node.html(template(data)); + this.$node.toggle(toggle); + this.markSelected(data.filter); + }; + + this.clearCompleted = function () { + this.trigger('uiClearRequested'); + }; + + this.after('initialize', function () { + this.$node.hide(); + this.on(document, 'dataStatsCounted', this.render); + this.on('click', { 'clearCompletedSelector': this.clearCompleted }); + }); } -); + + return defineComponent(stats, withFilters); +}); diff --git a/dependency-examples/flight/app/js/ui/todo_list.js b/dependency-examples/flight/app/js/ui/todo_list.js index 9b5588bd40..6e0f9fab57 100644 --- a/dependency-examples/flight/app/js/ui/todo_list.js +++ b/dependency-examples/flight/app/js/ui/todo_list.js @@ -1,113 +1,108 @@ -/*global define $ */ +/*global define, $ */ 'use strict'; -define( - [ - 'flight/component', - 'text!app/templates/todo.html', - '../utils' - ], - - function (defineComponent, todoTmpl, utils) { - return defineComponent(todoList); - - function todoList() { - var ENTER_KEY = 13; - var template = utils.tmpl(todoTmpl); - - this.defaultAttrs({ - destroySelector: 'button.destroy', - toggleSelector: 'input.toggle', - labelSelector: 'label', - editSelector: '.edit' - }); - - this.renderAll = function (e, data) { - this.$node.html(''); - data.todos.forEach(function (each) { - this.render(e, { todo: each }); - }, this); - }; - - this.render = function (e, data) { - if (e.type === 'dataTodoAdded' && data.filter === 'completed') { - return; - } - - this.$node.append(template(data.todo)); - }; - - this.edit = function (e, data) { - var $todoEl = $(data.el).parents('li'); - - $todoEl.addClass('editing'); - this.select('editSelector').focus(); - }; - - this.requestUpdate = function (e, data) { - var $inputEl = $(e.currentTarget); - var $todoEl = $inputEl.parents('li'); - var value = $inputEl.val().trim(); - var id = $todoEl.attr('id'); - - if (!$todoEl.hasClass('editing')) { - return; - } - - !$todoEl.removeClass('editing'); - - if (value) { - $todoEl.find('label').html(value); - this.trigger('uiUpdateRequested', { id: id, title: value }); - } else { - this.trigger('uiRemoveRequested', { id: id }); - } - }; - - this.requestUpdateOnEnter = function (e, data) { - if (e.which === ENTER_KEY) { - this.requestUpdate(e, data); - } - }; - - this.requestRemove = function (e, data) { - var id = $(data.el).attr('id').split('_')[1]; +define([ + 'flight/component', + 'text!app/templates/todo.html', + '../utils' +], function (defineComponent, todoTmpl, utils) { + function todoList() { + var ENTER_KEY = 13; + var template = utils.tmpl(todoTmpl); + + this.defaultAttrs({ + destroySelector: 'button.destroy', + toggleSelector: 'input.toggle', + labelSelector: 'label', + editSelector: '.edit' + }); + + this.renderAll = function (e, data) { + this.$node.html(''); + data.todos.forEach(function (each) { + this.render(e, { todo: each }); + }, this); + }; + + this.render = function (e, data) { + if (e.type === 'dataTodoAdded' && data.filter === 'completed') { + return; + } + + this.$node.append(template(data.todo)); + }; + + this.edit = function (e, data) { + var $todoEl = $(data.el).parents('li'); + + $todoEl.addClass('editing'); + this.select('editSelector').focus(); + }; + + this.requestUpdate = function (e) { + var $inputEl = $(e.currentTarget); + var $todoEl = $inputEl.parents('li'); + var value = $inputEl.val().trim(); + var id = $todoEl.attr('id'); + + if (!$todoEl.hasClass('editing')) { + return; + } + + $todoEl.removeClass('editing'); + + if (value) { + $todoEl.find('label').html(value); + this.trigger('uiUpdateRequested', { id: id, title: value }); + } else { this.trigger('uiRemoveRequested', { id: id }); - }; - - this.remove = function (e, data) { - var $todoEl = this.$node.find('#' + data.id); - $todoEl.remove(); - }; - - this.toggle = function (e, data) { - var $todoEl = $(data.el).parents('li'); - - $todoEl.toggleClass('completed'); - this.trigger('uiToggleRequested', { id: $todoEl.attr('id') }); - }; - - this.after('initialize', function () { - this.on(document, 'dataTodoAdded', this.render); - this.on(document, 'dataTodosLoaded', this.renderAll); - this.on(document, 'dataTodosFiltered', this.renderAll); - this.on(document, 'dataClearedCompleted', this.renderAll); - this.on(document, 'dataTodoToggledAll', this.renderAll); - this.on(document, 'dataTodoRemoved', this.remove); - - this.on('click', { 'destroySelector': this.requestRemove }); - this.on('click', { 'toggleSelector': this.toggle }); - this.on('dblclick', { 'labelSelector': this.edit }); - - this.$node.on('blur', '.edit', this.bind(this.requestUpdate)); - this.$node.on('keydown', '.edit', this.bind(this.requestUpdateOnEnter)); - - // these don't work - // this.on(this.attr.editSelector, 'blur', this.requestUpdate); - // this.on('blur', { 'editSelector': this.requestUpdate }); - - this.trigger('uiLoadRequested'); - }); - } + } + }; + + this.requestUpdateOnEnter = function (e, data) { + if (e.which === ENTER_KEY) { + this.requestUpdate(e, data); + } + }; + + this.requestRemove = function (e, data) { + var id = $(data.el).attr('id').split('_')[1]; + this.trigger('uiRemoveRequested', { id: id }); + }; + + this.remove = function (e, data) { + var $todoEl = this.$node.find('#' + data.id); + $todoEl.remove(); + }; + + this.toggle = function (e, data) { + var $todoEl = $(data.el).parents('li'); + + $todoEl.toggleClass('completed'); + this.trigger('uiToggleRequested', { id: $todoEl.attr('id') }); + }; + + this.after('initialize', function () { + this.on(document, 'dataTodoAdded', this.render); + this.on(document, 'dataTodosLoaded', this.renderAll); + this.on(document, 'dataTodosFiltered', this.renderAll); + this.on(document, 'dataTodoToggledAll', this.renderAll); + this.on(document, 'dataTodoRemoved', this.remove); + + this.on('click', { 'destroySelector': this.requestRemove }); + this.on('click', { 'toggleSelector': this.toggle }); + this.on('dblclick', { 'labelSelector': this.edit }); + + this.$node.on('blur', '.edit', this.bind(this.requestUpdate)); + this.$node.on('keydown', '.edit', this.bind(this.requestUpdateOnEnter)); + + // these don't work + // this.on(this.attr.editSelector, 'blur', this.requestUpdate); + // this.on('blur', { 'editSelector': this.requestUpdate }); + + this.trigger('uiLoadRequested'); + }); } -); + + return defineComponent(todoList); +}); diff --git a/dependency-examples/flight/app/js/ui/toggle_all.js b/dependency-examples/flight/app/js/ui/toggle_all.js index 927ce9c514..f4334dbaa0 100644 --- a/dependency-examples/flight/app/js/ui/toggle_all.js +++ b/dependency-examples/flight/app/js/ui/toggle_all.js @@ -1,29 +1,25 @@ /*global define */ 'use strict'; -define( - [ - 'flight/component' - ], - - function (defineComponent) { - return defineComponent(toggleAll); - - function toggleAll() { - this.toggleAllComplete = function () { - this.trigger('uiToggleAllRequested', { - completed: this.$node.is(':checked') - }); - }; +define([ + 'flight/component' +], function (defineComponent) { + function toggleAll() { + this.toggleAllComplete = function () { + this.trigger('uiToggleAllRequested', { + completed: this.$node.is(':checked') + }); + }; - this.toggleCheckbox = function (e, data) { - this.$node[0].checked = !data.remaining; - }; + this.toggleCheckbox = function (e, data) { + this.$node[0].checked = !data.remaining; + }; - this.after('initialize', function () { - this.on('click', this.toggleAllComplete); - this.on(document, 'dataStatsCounted', this.toggleCheckbox); - }); - } + this.after('initialize', function () { + this.on('click', this.toggleAllComplete); + this.on(document, 'dataStatsCounted', this.toggleCheckbox); + }); } -); + + return defineComponent(toggleAll); +}); diff --git a/dependency-examples/flight/app/js/ui/with_filters.js b/dependency-examples/flight/app/js/ui/with_filters.js index c6a4a949e0..ea7287b45c 100644 --- a/dependency-examples/flight/app/js/ui/with_filters.js +++ b/dependency-examples/flight/app/js/ui/with_filters.js @@ -1,28 +1,26 @@ -/*global define $ */ +/*global define, $ */ 'use strict'; -define( - function () { - return function withFilters() { - this.defaultAttrs({ - filterSelector: '#filters a' - }); +define(function () { + return function withFilters() { + this.defaultAttrs({ + filterSelector: '#filters a' + }); - this.chooseFilter = function (e, data) { - var filter = data.el.hash.slice(2); + this.chooseFilter = function (e, data) { + var filter = data.el.hash.slice(2); - this.select('filterSelector').removeClass('selected'); - $(data.el).addClass('selected'); - this.trigger('uiFilterRequested', { filter: filter }); - }; - - this.markSelected = function (filter) { - this.$node.find('[href="#/' + filter + '"]').addClass('selected'); - }; + this.select('filterSelector').removeClass('selected'); + $(data.el).addClass('selected'); + this.trigger('uiFilterRequested', { filter: filter }); + }; - this.after('initialize', function () { - this.on('click', { filterSelector: this.chooseFilter }); - }); + this.markSelected = function (filter) { + this.$node.find('[href="#/' + filter + '"]').addClass('selected'); }; - } -); + + this.after('initialize', function () { + this.on('click', { filterSelector: this.chooseFilter }); + }); + }; +}); diff --git a/dependency-examples/flight/app/js/utils.js b/dependency-examples/flight/app/js/utils.js index 89edf57731..fc1101bce0 100644 --- a/dependency-examples/flight/app/js/utils.js +++ b/dependency-examples/flight/app/js/utils.js @@ -4,7 +4,6 @@ // tmpl function scooped from underscore. // http://documentcloud.github.com/underscore/#template define(function () { - var _ = {}; // List of HTML entities for escaping. @@ -108,6 +107,7 @@ define(function () { source + "return __p;\n"; try { + /*jshint evil:true */ render = new Function(settings.variable || 'obj', '_', source); } catch (err) { err.source = source; @@ -128,5 +128,7 @@ define(function () { return template; }; - return { tmpl: template }; + return { + tmpl: template + }; }); diff --git a/dependency-examples/flight/app/templates/stats.html b/dependency-examples/flight/app/templates/stats.html index 81dafe4357..c945aa54b6 100644 --- a/dependency-examples/flight/app/templates/stats.html +++ b/dependency-examples/flight/app/templates/stats.html @@ -1,4 +1,6 @@ -<%= remaining %> <%= remaining == 1 ? 'item' : 'items' %> left + + <%= remaining %> <%= remaining == 1 ? 'item' : 'items' %> left +
                  • All @@ -11,5 +13,5 @@
                  <% if (completed) { %> - + <% } %> diff --git a/dependency-examples/flight/bower_components/todomvc-common/base.css b/dependency-examples/flight/bower_components/todomvc-common/base.css index 8d1db3a696..3e6bfaf38d 100644 --- a/dependency-examples/flight/bower_components/todomvc-common/base.css +++ b/dependency-examples/flight/bower_components/todomvc-common/base.css @@ -61,7 +61,7 @@ body { font-style: italic; } -#todoapp input:-moz-placeholder { +#todoapp input::-moz-placeholder { font-style: italic; color: #a9a9a9; } @@ -412,3 +412,144 @@ label[for='toggle-all'] { .hidden{ display:none; } + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/dependency-examples/flight/bower_components/todomvc-common/base.js b/dependency-examples/flight/bower_components/todomvc-common/base.js index 3fd166d061..099da60dd1 100644 --- a/dependency-examples/flight/bower_components/todomvc-common/base.js +++ b/dependency-examples/flight/bower_components/todomvc-common/base.js @@ -1,38 +1,209 @@ (function () { 'use strict'; + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + if (location.hostname === 'todomvc.com') { window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); } - function getSourcePath() { - // If accessed via addyosmani.github.io/todomvc/, strip the project path. - if (location.hostname.indexOf('github.io') > 0) { - return location.pathname.replace(/todomvc\//, ''); + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); } - return location.pathname; } - function appendSourceLink() { - var sourceLink = document.createElement('a'); - var paragraph = document.createElement('p'); - var footer = document.getElementById('info'); - var urlBase = 'https://github.com/addyosmani/todomvc/tree/gh-pages'; + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } - if (footer) { - sourceLink.href = urlBase + getSourcePath(); - sourceLink.appendChild(document.createTextNode('Check out the source')); - paragraph.appendChild(sourceLink); - footer.appendChild(paragraph); + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; } - function redirect() { - if (location.hostname === 'addyosmani.github.io') { - location.href = location.href.replace('addyosmani.github.io/todomvc', 'todomvc.com'); + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); } } - appendSourceLink(); + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + redirect(); + getFile('learn.json', Learn); })(); diff --git a/dependency-examples/flight/index.html b/dependency-examples/flight/index.html index 572fc4f4ad..9235c71952 100644 --- a/dependency-examples/flight/index.html +++ b/dependency-examples/flight/index.html @@ -1,8 +1,8 @@ - + - + Flight • Todo diff --git a/dependency-examples/flight/readme.md b/dependency-examples/flight/readme.md new file mode 100644 index 0000000000..ce5de1ee54 --- /dev/null +++ b/dependency-examples/flight/readme.md @@ -0,0 +1,19 @@ +# Flight TodoMVC Example + +> Flight is a lightweight, component-based JavaScript framework that maps behavior to DOM nodes. + +> _[Flight - flightjs.github.io](http://flightjs.github.io)_ + + +## Learning Flight + +The [Flight website](http://flightjs.github.io) is a great resource for getting started. + +Here are some links you may find helpful: + +* [GitHub](https://github.com/flightjs/flight) +* [Demo Application](http://twitter.github.io/flight/demo) +* [Installation](https://github.com/flightjs/flight/blob/master/README.md#installation) +* [Flight on Twitter](http://twitter.com/flight) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ diff --git a/index.html b/index.html index bee70eaafe..994803405d 100644 --- a/index.html +++ b/index.html @@ -1,319 +1,326 @@ - - - TodoMVC - - - - - - - - - - - - - - -
                  -
                  -
                  - -

                  Helping you select an MV* framework

                  - -
                  -
                  - TodoMVC -
                  -
                  -
                  -
                  -

                  Introduction

                  -

                  Developers these days are spoiled with choice when it comes to selecting an MV* framework for structuring and organizing their JavaScript web apps.

                  -

                  Backbone, Ember, AngularJS, Spine... the list of new and stable solutions continues to grow, but just how do you decide on which to use in a sea of so many options?

                  -

                  To help solve this problem, we created TodoMVC - a project which offers the same Todo application implemented using MV* concepts in most of the popular JavaScript MV* frameworks of today.

                  - - -
                  -
                  -
                  -

                  JavaScript Apps

                  - +
                  +

                  Compile To JavaScript

                  + +
                  +

                  MVC Extension Frameworks

                  + +
                  +

                  Module Loaders

                  + +
                  +

                  Real-time

                  + +
                  +

                  Compare these to a non-framework implementation

                  + +

                  * R = App also demonstrates routing

                  +

                  * Maroon = App requires further work to be spec-compliant

                  +
                  -
                  - Todo app screenshot +
                  +
                  +
                  +
                  +

                  +
                  + + +
                  +
                  +
                  +
                  + Todo app screenshot +
                  -
                  -
                  -
                  -
                  -

                  New in 1.1 - 2013-02-14

                  -
                  -
                  -

                  Selecting a Framework

                  -

                  Once you've downloaded the latest release and played around with the apps, you'll want to decide on a specific framework to try out.

                  -

                  Study the syntax required for defining models, views and (where applicable) controllers and classes in the frameworks you're interested in and try your hand at editing the code to see how it feels using it first-hand.

                  -

                  Please ensure that if you're happy with this, you do spend more time investigating the framework (including reading the official docs, the source and its complete feature list). There's often a lot more to a framework than what we present in our examples.

                  +
                  +
                  +

                  Selecting a Framework

                  +

                  Once you've downloaded the latest release and played around with the apps, you'll want to decide on a specific framework to try out.

                  +

                  Study the syntax required for defining models, views and (where applicable) controllers and classes in the frameworks you're interested in and try your hand at editing the code to see how it feels using it first-hand.

                  +

                  Please ensure that if you're happy with this, you do spend more time investigating the framework (including reading the official docs, the source and its complete feature list). There's often a lot more to a framework than what we present in our examples.

                  +
                  +
                  +

                  Getting Involved

                  +

                  Is there a bug we haven't fixed or an MV* framework you feel would benefit from being included in TodoMVC?

                  +

                  If so, feel free to fork the repo, read our contribution guidelines, and submit a pull request — we'll be happy to review it for inclusion.

                  +

                  Make sure you use the template as a starting point and read the app specification.

                  +

                  + Submit Pull Request » +

                  +
                  -
                  -

                  Getting Involved

                  -

                  Is there a bug we haven't fixed or an MV* framework you feel would benefit from being included in TodoMVC?

                  -

                  If so, feel free to fork the repo, read our contribution guidelines, and submit a pull request — we'll be happy to review it for inclusion.

                  -

                  Make sure you use the template as a starting point and read the app specification.

                  -

                  - Submit Pull Request » +


                  +
                  +
                  -
                  - - - - - - - - - + + + + + + + diff --git a/labs/architecture-examples/ariatemplates/bower.json b/labs/architecture-examples/ariatemplates/bower.json new file mode 100644 index 0000000000..e43423491b --- /dev/null +++ b/labs/architecture-examples/ariatemplates/bower.json @@ -0,0 +1,7 @@ +{ + "name": "todomvc-ariatemplates", + "version": "0.0.0", + "dependencies": { + "todomvc-common": "~0.1.6" + } +} diff --git a/labs/architecture-examples/ariatemplates/bower_components/todomvc-common/base.css b/labs/architecture-examples/ariatemplates/bower_components/todomvc-common/base.css new file mode 100644 index 0000000000..3e6bfaf38d --- /dev/null +++ b/labs/architecture-examples/ariatemplates/bower_components/todomvc-common/base.css @@ -0,0 +1,555 @@ +html, +body { + margin: 0; + padding: 0; +} + +button { + margin: 0; + padding: 0; + border: 0; + background: none; + font-size: 100%; + vertical-align: baseline; + font-family: inherit; + color: inherit; + -webkit-appearance: none; + /*-moz-appearance: none;*/ + -ms-appearance: none; + -o-appearance: none; + appearance: none; +} + +body { + font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; + line-height: 1.4em; + background: #eaeaea url('bg.png'); + color: #4d4d4d; + width: 550px; + margin: 0 auto; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + -ms-font-smoothing: antialiased; + -o-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +#todoapp { + background: #fff; + background: rgba(255, 255, 255, 0.9); + margin: 130px 0 40px 0; + border: 1px solid #ccc; + position: relative; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2), + 0 25px 50px 0 rgba(0, 0, 0, 0.15); +} + +#todoapp:before { + content: ''; + border-left: 1px solid #f5d6d6; + border-right: 1px solid #f5d6d6; + width: 2px; + position: absolute; + top: 0; + left: 40px; + height: 100%; +} + +#todoapp input::-webkit-input-placeholder { + font-style: italic; +} + +#todoapp input::-moz-placeholder { + font-style: italic; + color: #a9a9a9; +} + +#todoapp h1 { + position: absolute; + top: -120px; + width: 100%; + font-size: 70px; + font-weight: bold; + text-align: center; + color: #b3b3b3; + color: rgba(255, 255, 255, 0.3); + text-shadow: -1px -1px rgba(0, 0, 0, 0.2); + -webkit-text-rendering: optimizeLegibility; + -moz-text-rendering: optimizeLegibility; + -ms-text-rendering: optimizeLegibility; + -o-text-rendering: optimizeLegibility; + text-rendering: optimizeLegibility; +} + +#header { + padding-top: 15px; + border-radius: inherit; +} + +#header:before { + content: ''; + position: absolute; + top: 0; + right: 0; + left: 0; + height: 15px; + z-index: 2; + border-bottom: 1px solid #6c615c; + background: #8d7d77; + background: -webkit-gradient(linear, left top, left bottom, from(rgba(132, 110, 100, 0.8)),to(rgba(101, 84, 76, 0.8))); + background: -webkit-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8)); + background: -moz-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8)); + background: -o-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8)); + background: -ms-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8)); + background: linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8)); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670'); + border-top-left-radius: 1px; + border-top-right-radius: 1px; +} + +#new-todo, +.edit { + position: relative; + margin: 0; + width: 100%; + font-size: 24px; + font-family: inherit; + line-height: 1.4em; + border: 0; + outline: none; + color: inherit; + padding: 6px; + border: 1px solid #999; + box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + -o-box-sizing: border-box; + box-sizing: border-box; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + -ms-font-smoothing: antialiased; + -o-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +#new-todo { + padding: 16px 16px 16px 60px; + border: none; + background: rgba(0, 0, 0, 0.02); + z-index: 2; + box-shadow: none; +} + +#main { + position: relative; + z-index: 2; + border-top: 1px dotted #adadad; +} + +label[for='toggle-all'] { + display: none; +} + +#toggle-all { + position: absolute; + top: -42px; + left: -4px; + width: 40px; + text-align: center; + border: none; /* Mobile Safari */ +} + +#toggle-all:before { + content: '»'; + font-size: 28px; + color: #d9d9d9; + padding: 0 25px 7px; +} + +#toggle-all:checked:before { + color: #737373; +} + +#todo-list { + margin: 0; + padding: 0; + list-style: none; +} + +#todo-list li { + position: relative; + font-size: 24px; + border-bottom: 1px dotted #ccc; +} + +#todo-list li:last-child { + border-bottom: none; +} + +#todo-list li.editing { + border-bottom: none; + padding: 0; +} + +#todo-list li.editing .edit { + display: block; + width: 506px; + padding: 13px 17px 12px 17px; + margin: 0 0 0 43px; +} + +#todo-list li.editing .view { + display: none; +} + +#todo-list li .toggle { + text-align: center; + width: 40px; + /* auto, since non-WebKit browsers doesn't support input styling */ + height: auto; + position: absolute; + top: 0; + bottom: 0; + margin: auto 0; + border: none; /* Mobile Safari */ + -webkit-appearance: none; + /*-moz-appearance: none;*/ + -ms-appearance: none; + -o-appearance: none; + appearance: none; +} + +#todo-list li .toggle:after { + content: '✔'; + line-height: 43px; /* 40 + a couple of pixels visual adjustment */ + font-size: 20px; + color: #d9d9d9; + text-shadow: 0 -1px 0 #bfbfbf; +} + +#todo-list li .toggle:checked:after { + color: #85ada7; + text-shadow: 0 1px 0 #669991; + bottom: 1px; + position: relative; +} + +#todo-list li label { + word-break: break-word; + padding: 15px; + margin-left: 45px; + display: block; + line-height: 1.2; + -webkit-transition: color 0.4s; + -moz-transition: color 0.4s; + -ms-transition: color 0.4s; + -o-transition: color 0.4s; + transition: color 0.4s; +} + +#todo-list li.completed label { + color: #a9a9a9; + text-decoration: line-through; +} + +#todo-list li .destroy { + display: none; + position: absolute; + top: 0; + right: 10px; + bottom: 0; + width: 40px; + height: 40px; + margin: auto 0; + font-size: 22px; + color: #a88a8a; + -webkit-transition: all 0.2s; + -moz-transition: all 0.2s; + -ms-transition: all 0.2s; + -o-transition: all 0.2s; + transition: all 0.2s; +} + +#todo-list li .destroy:hover { + text-shadow: 0 0 1px #000, + 0 0 10px rgba(199, 107, 107, 0.8); + -webkit-transform: scale(1.3); + -moz-transform: scale(1.3); + -ms-transform: scale(1.3); + -o-transform: scale(1.3); + transform: scale(1.3); +} + +#todo-list li .destroy:after { + content: '✖'; +} + +#todo-list li:hover .destroy { + display: block; +} + +#todo-list li .edit { + display: none; +} + +#todo-list li.editing:last-child { + margin-bottom: -1px; +} + +#footer { + color: #777; + padding: 0 15px; + position: absolute; + right: 0; + bottom: -31px; + left: 0; + height: 20px; + z-index: 1; + text-align: center; +} + +#footer:before { + content: ''; + position: absolute; + right: 0; + bottom: 31px; + left: 0; + height: 50px; + z-index: -1; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3), + 0 6px 0 -3px rgba(255, 255, 255, 0.8), + 0 7px 1px -3px rgba(0, 0, 0, 0.3), + 0 43px 0 -6px rgba(255, 255, 255, 0.8), + 0 44px 2px -6px rgba(0, 0, 0, 0.2); +} + +#todo-count { + float: left; + text-align: left; +} + +#filters { + margin: 0; + padding: 0; + list-style: none; + position: absolute; + right: 0; + left: 0; +} + +#filters li { + display: inline; +} + +#filters li a { + color: #83756f; + margin: 2px; + text-decoration: none; +} + +#filters li a.selected { + font-weight: bold; +} + +#clear-completed { + float: right; + position: relative; + line-height: 20px; + text-decoration: none; + background: rgba(0, 0, 0, 0.1); + font-size: 11px; + padding: 0 10px; + border-radius: 3px; + box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.2); +} + +#clear-completed:hover { + background: rgba(0, 0, 0, 0.15); + box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.3); +} + +#info { + margin: 65px auto 0; + color: #a6a6a6; + font-size: 12px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7); + text-align: center; +} + +#info a { + color: inherit; +} + +/* + Hack to remove background from Mobile Safari. + Can't use it globally since it destroys checkboxes in Firefox and Opera +*/ +@media screen and (-webkit-min-device-pixel-ratio:0) { + #toggle-all, + #todo-list li .toggle { + background: none; + } + + #todo-list li .toggle { + height: 40px; + } + + #toggle-all { + top: -56px; + left: -15px; + width: 65px; + height: 41px; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); + -webkit-appearance: none; + appearance: none; + } +} + +.hidden{ + display:none; +} + +hr { + margin: 20px 0; + border: 0; + border-top: 1px dashed #C5C5C5; + border-bottom: 1px dashed #F7F7F7; +} + +.learn a { + font-weight: normal; + text-decoration: none; + color: #b83f45; +} + +.learn a:hover { + text-decoration: underline; + color: #787e7e; +} + +.learn h3, +.learn h4, +.learn h5 { + margin: 10px 0; + font-weight: 500; + line-height: 1.2; + color: #000; +} + +.learn h3 { + font-size: 24px; +} + +.learn h4 { + font-size: 18px; +} + +.learn h5 { + margin-bottom: 0; + font-size: 14px; +} + +.learn ul { + padding: 0; + margin: 0 0 30px 25px; +} + +.learn li { + line-height: 20px; +} + +.learn p { + font-size: 15px; + font-weight: 300; + line-height: 1.3; + margin-top: 0; + margin-bottom: 0; +} + +.quote { + border: none; + margin: 20px 0 60px 0; +} + +.quote p { + font-style: italic; +} + +.quote p:before { + content: '“'; + font-size: 50px; + opacity: .15; + position: absolute; + top: -20px; + left: 3px; +} + +.quote p:after { + content: '”'; + font-size: 50px; + opacity: .15; + position: absolute; + bottom: -42px; + right: 3px; +} + +.quote footer { + position: absolute; + bottom: -40px; + right: 0; +} + +.quote footer img { + border-radius: 3px; +} + +.quote footer a { + margin-left: 5px; + vertical-align: middle; +} + +.speech-bubble { + position: relative; + padding: 10px; + background: rgba(0, 0, 0, .04); + border-radius: 5px; +} + +.speech-bubble:after { + content: ''; + position: absolute; + top: 100%; + right: 30px; + border: 13px solid transparent; + border-top-color: rgba(0, 0, 0, .04); +} + +/**body*/.learn-bar > .learn { + position: absolute; + width: 272px; + top: 8px; + left: -300px; + padding: 10px; + border-radius: 5px; + background-color: rgba(255, 255, 255, .6); + transition-property: left; + transition-duration: 500ms; +} + +@media (min-width: 899px) { + /**body*/.learn-bar { + width: auto; + margin: 0 0 0 300px; + } + /**body*/.learn-bar > .learn { + left: 8px; + } + /**body*/.learn-bar #todoapp { + width: 550px; + margin: 130px auto 40px auto; + } +} diff --git a/labs/architecture-examples/ariatemplates/bower_components/todomvc-common/base.js b/labs/architecture-examples/ariatemplates/bower_components/todomvc-common/base.js new file mode 100644 index 0000000000..099da60dd1 --- /dev/null +++ b/labs/architecture-examples/ariatemplates/bower_components/todomvc-common/base.js @@ -0,0 +1,209 @@ +(function () { + 'use strict'; + + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + } + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + + if (location.hostname === 'todomvc.com') { + window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script')); + } + + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); + } + } + + function findRoot() { + var base; + + [/labs/, /\w*-examples/].forEach(function (href) { + var match = location.href.match(href); + + if (!base && match) { + base = location.href.indexOf(match); + } + }); + + return location.href.substr(0, base); + } + + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); + } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; + } + + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').getAttribute('data-framework'); + } + + + if (template && learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.template = template; + + this.append(); + } + } + + Learn.prototype.append = function () { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + }); + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + + redirect(); + getFile('learn.json', Learn); +})(); diff --git a/labs/architecture-examples/ariatemplates/bower_components/todomvc-common/bg.png b/labs/architecture-examples/ariatemplates/bower_components/todomvc-common/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..b2a7600825ee11f21849ed475499c7d1ecbcc870 GIT binary patch literal 2126 zcmV-U2(kBxP)+9y`=HK7nt=~3t000O5Nklm=04hVa_lXl_bm=+M;=eI<%$rO2ta`suh*Sr#POw*?adq!O!CV z*0&b)rkCCEV)1nIuiLBntUH-MJI;&qYgz|d@Nhnn_abi2g`pu4NAMVid3hS%?quz~ zjlJf(x8cj{VS zUVEP1msg9`^OFUhSO5rtXHhRlyU2i>6$BT=glG`{JlctGHrwRIm)6Buu65jLQn^H8 zvl9lZqUBA+%qvM5XC+yY@mfA(YB~XP=e|6<{%$^eU8nrK?v2ccb@Jom5CG>rKAL7J zplHEIavVp|0p1&m!G`Ti?<7iZ;}@G7#Z)}Km%2!FHnQ0*&?PLR)G!HAaHgU#c|$dz zpj#0HmeadIe>`#)=Jjkb{B=FKnU3pc-&Y@j_j6(h4Y~+Uq!^J=LHunx1xi4QXK-Y{&MoT8ky6Vb9c|WhnOwF~c=3zOy8agktliS6# z`#8F`9H)D=bmk9B5MnW&_r#)f$c+;$LSr-@^An8dhc~Iquuv>jOK7pw7LJ;&X0i1C zGMsHdP1Os@ny$$j!>XAii%7bp5k>`pyNA!~epb)()p9zR4Yl6z=U}{CIdh1z(FpAo zQIW!;0zpCyC4*7YLkZCO@cul0R_&zghsA8Ek)z%jNpKa92{@NH+SstX%@}xB*Jk!l}PZ1cClIns~}5^!RncUk*rmA z%SIVgt58EQxLJ+OiFqKkBuwquyZLUp|gr zPUbUbFbBrPd1xO`^C*r-i3p9*F#(OBh!4Wy@aC&*!|O|GXcjDA&YhF{;cD7*o(GS^ z@pQSE7)x_81=Qyje6*LQ#TXu-7(o;S8u3tpDA0_ddj%hmCspeXdhYR}-i9A=C`EoChUYuH~^x!9+|&(Pgb*>Ck<=9j|)*@xyfT zpP#+Kt<}39b|3Wl4fxT(+G?aH>gG^d@MEaUOJRfy55TtFI7^Y)VuMU=7Pp0y55jS~ z+TJ)igMyrqkX;wU8j68iIDtqJYhS_D3_Oem-@g6me_RfiQ}uT_K-A-9qG%}gk3E9c z!8`KgsMNXm)beloPfMql*|&$M>1q`i!cY)RFYnjNYu*gSv@8XebV7%}xYL>6)GJPJ zJpA7K31lcJuIFKSw-{x4FX0K2Az)~Xg<`sOu$4|^-(^XJX4YzoiNRvL zyuY7~26w-P^Zw%6F}shBwV2$02c8RsSUy6dM92diCAxiX3IUqsq5ig6>U_!Vy*q5$ zjm}16tJr+QZ&T?HkkpeIwVX-r1EI=@%Zlt;6g*mj&E!A))%gXJ=x6u#l zcKEP>bx4rqV*k`BBrZ$Mqjt{TsHcxUH>;)iAK}B(Kila&VD%b?6m&^0WK4^&EZNAI z8AMYs_%$D%|M+@+cQqL-hi4yG>h*jwdii!W1{}p>ZhwFYt_4Su1kjY9<-5`!$VNOI1y(EDSH4WpCijE_>al!Nt=^eVER#uJ1=b z;BWF2IgyF5LexV+yec$Kin;Ai@myo;G>zJ&jrdW#ecXhIZph5OYqw_PEfcF56Z5Zu_ZZE#q3Mc+N&1O^7hoh9QR7`+L$cBP5pqG=fqA0uh zUBukaxTFmH)<|Xbvp2c=HSbNkpXw73a5lv7V$jb92#yZ141@$X?F}Jt8gIU7Wm6m9 z?e_;;zsnm6`LZeP>T=$)Kr>Z?kr*UmFqR7zx0C6^bmcsc@1AGtw_rNH>-Xm$d*|Q< zn&1Ln0u7=l&ILs>%CkJp`DiG9F18x4Ne+lg<#i?e7jL%x;4ZnRkN^Mx07*qoM6N<$ Ef(>0N!2kdN literal 0 HcmV?d00001 diff --git a/labs/architecture-examples/ariatemplates/index.html b/labs/architecture-examples/ariatemplates/index.html index 76e19072c3..c7d4709e14 100644 --- a/labs/architecture-examples/ariatemplates/index.html +++ b/labs/architecture-examples/ariatemplates/index.html @@ -1,41 +1,39 @@ - - - - - Aria Templates • TodoMVC - - - - + + + + + Aria Templates • TodoMVC + + + + +
                  +
                  - -
                  + + + - - - - - + + diff --git a/labs/architecture-examples/ariatemplates/readme.md b/labs/architecture-examples/ariatemplates/readme.md new file mode 100644 index 0000000000..77883a1e20 --- /dev/null +++ b/labs/architecture-examples/ariatemplates/readme.md @@ -0,0 +1,27 @@ +# Aria Templates TodoMVC Example + +> Aria Templates (aka AT) is an application framework written in JavaScript for building rich and large-scaled enterprise web applications. + +> _[Aria Templates - ariatemplates.com](http://ariatemplates.com)_ + + +## Learning Aria Templates + +The [Aria Templates website](http://ariatemplates.com) is a great resource for getting started. + +Here are some links you may find helpful: + +* [Documentation](http://ariatemplates.com/usermanual) +* [API Reference](http://ariatemplates.com/aria/guide/apps/apidocs) +* [Guides](http://ariatemplates.com/guides) +* [Blog](http://ariatemplates.com/blog) +* [FAQ](http://ariatemplates.com/faq) +* [Aria Templates on GitHub](https://github.com/ariatemplates) + +Get help from other Aria Templates users: + +* [Aria Templates on StackOverflow](http://stackoverflow.com/questions/tagged/ariatemplates) +* [Forums](http://ariatemplates.com/forum) +* [Aria Templates on Twitter](http://twitter.com/ariatemplates) + +_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._ diff --git a/labs/architecture-examples/backbone.xmpp/bower.json b/labs/architecture-examples/backbone.xmpp/bower.json new file mode 100644 index 0000000000..5d7e906296 --- /dev/null +++ b/labs/architecture-examples/backbone.xmpp/bower.json @@ -0,0 +1,11 @@ +{ + "name": "backbone.xmpp", + "version": "0.0.0", + "dependencies": { + "todomvc-common": "~0.1.6", + "jquery": "~2.0.0", + "lodash": "~1.2.1", + "backbone": "~1.0.0", + "Strophe.js": "~1.0.2" + } +} \ No newline at end of file diff --git a/labs/architecture-examples/backbone.xmpp/js/lib/strophe.js b/labs/architecture-examples/backbone.xmpp/bower_components/Strophe.js/strophe.js similarity index 84% rename from labs/architecture-examples/backbone.xmpp/js/lib/strophe.js rename to labs/architecture-examples/backbone.xmpp/bower_components/Strophe.js/strophe.js index c802b366d3..660d623e76 100644 --- a/labs/architecture-examples/backbone.xmpp/js/lib/strophe.js +++ b/labs/architecture-examples/backbone.xmpp/bower_components/Strophe.js/strophe.js @@ -78,213 +78,6 @@ var Base64 = (function () { return obj; })(); -/* - * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined - * in FIPS PUB 180-1 - * Version 2.1a Copyright Paul Johnston 2000 - 2002. - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * Distributed under the BSD License - * See http://pajhome.org.uk/crypt/md5 for details. - */ - -/* - * Configurable variables. You may need to tweak these to be compatible with - * the server-side, but the defaults work in most cases. - */ -var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ -var b64pad = "="; /* base-64 pad character. "=" for strict RFC compliance */ -var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ - -/* - * These are the functions you'll usually want to call - * They take string arguments and return either hex or base-64 encoded strings - */ -function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));} -function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));} -function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));} -function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));} -function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));} -function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));} - -/* - * Perform a simple self-test to see if the VM is working - */ -function sha1_vm_test() -{ - return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; -} - -/* - * Calculate the SHA-1 of an array of big-endian words, and a bit length - */ -function core_sha1(x, len) -{ - /* append padding */ - x[len >> 5] |= 0x80 << (24 - len % 32); - x[((len + 64 >> 9) << 4) + 15] = len; - - var w = new Array(80); - var a = 1732584193; - var b = -271733879; - var c = -1732584194; - var d = 271733878; - var e = -1009589776; - - var i, j, t, olda, oldb, oldc, oldd, olde; - for (i = 0; i < x.length; i += 16) - { - olda = a; - oldb = b; - oldc = c; - oldd = d; - olde = e; - - for (j = 0; j < 80; j++) - { - if (j < 16) { w[j] = x[i + j]; } - else { w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); } - t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), - safe_add(safe_add(e, w[j]), sha1_kt(j))); - e = d; - d = c; - c = rol(b, 30); - b = a; - a = t; - } - - a = safe_add(a, olda); - b = safe_add(b, oldb); - c = safe_add(c, oldc); - d = safe_add(d, oldd); - e = safe_add(e, olde); - } - return [a, b, c, d, e]; -} - -/* - * Perform the appropriate triplet combination function for the current - * iteration - */ -function sha1_ft(t, b, c, d) -{ - if (t < 20) { return (b & c) | ((~b) & d); } - if (t < 40) { return b ^ c ^ d; } - if (t < 60) { return (b & c) | (b & d) | (c & d); } - return b ^ c ^ d; -} - -/* - * Determine the appropriate additive constant for the current iteration - */ -function sha1_kt(t) -{ - return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : - (t < 60) ? -1894007588 : -899497514; -} - -/* - * Calculate the HMAC-SHA1 of a key and some data - */ -function core_hmac_sha1(key, data) -{ - var bkey = str2binb(key); - if (bkey.length > 16) { bkey = core_sha1(bkey, key.length * chrsz); } - - var ipad = new Array(16), opad = new Array(16); - for (var i = 0; i < 16; i++) - { - ipad[i] = bkey[i] ^ 0x36363636; - opad[i] = bkey[i] ^ 0x5C5C5C5C; - } - - var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); - return core_sha1(opad.concat(hash), 512 + 160); -} - -/* - * Add integers, wrapping at 2^32. This uses 16-bit operations internally - * to work around bugs in some JS interpreters. - */ -function safe_add(x, y) -{ - var lsw = (x & 0xFFFF) + (y & 0xFFFF); - var msw = (x >> 16) + (y >> 16) + (lsw >> 16); - return (msw << 16) | (lsw & 0xFFFF); -} - -/* - * Bitwise rotate a 32-bit number to the left. - */ -function rol(num, cnt) -{ - return (num << cnt) | (num >>> (32 - cnt)); -} - -/* - * Convert an 8-bit or 16-bit string to an array of big-endian words - * In 8-bit function, characters >255 have their hi-byte silently ignored. - */ -function str2binb(str) -{ - var bin = []; - var mask = (1 << chrsz) - 1; - for (var i = 0; i < str.length * chrsz; i += chrsz) - { - bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); - } - return bin; -} - -/* - * Convert an array of big-endian words to a string - */ -function binb2str(bin) -{ - var str = ""; - var mask = (1 << chrsz) - 1; - for (var i = 0; i < bin.length * 32; i += chrsz) - { - str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask); - } - return str; -} - -/* - * Convert an array of big-endian words to a hex string. - */ -function binb2hex(binarray) -{ - var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; - var str = ""; - for (var i = 0; i < binarray.length * 4; i++) - { - str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + - hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); - } - return str; -} - -/* - * Convert an array of big-endian words to a base-64 string - */ -function binb2b64(binarray) -{ - var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - var str = ""; - var triplet, j; - for (var i = 0; i < binarray.length * 4; i += 3) - { - triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16) | - (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) | - ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF); - for (j = 0; j < 4; j++) - { - if (i * 8 + j * 6 > binarray.length * 32) { str += b64pad; } - else { str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); } - } - } - return str; -} /* * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message * Digest Algorithm, as defined in RFC 1321. @@ -612,7 +405,7 @@ if (!Function.prototype.bind) { var _slice = Array.prototype.slice; var _concat = Array.prototype.concat; var _args = _slice.call(arguments, 1); - + return function () { return func.apply(obj ? obj : this, _concat.call(_args, @@ -721,7 +514,7 @@ Strophe = { * The version of the Strophe library. Unreleased builds will have * a version of head-HASH where HASH is a partial revision. */ - VERSION: "", + VERSION: "1.0.2", /** Constants: XMPP Namespace Constants * Common namespace constants from the XMPP RFCs and XEPs. @@ -739,8 +532,6 @@ Strophe = { * NS.STREAM - XMPP Streams namespace from RFC 3920. * NS.BIND - XMPP Binding namespace from RFC 3920. * NS.SESSION - XMPP Session namespace from RFC 3920. - * NS.XHTML_IM - XHTML-IM namespace from XEP 71. - * NS.XHTML - XHTML body namespace from XEP 71. */ NS: { HTTPBIND: "http://jabber.org/protocol/httpbind", @@ -757,68 +548,10 @@ Strophe = { BIND: "urn:ietf:params:xml:ns:xmpp-bind", SESSION: "urn:ietf:params:xml:ns:xmpp-session", VERSION: "jabber:iq:version", - STANZAS: "urn:ietf:params:xml:ns:xmpp-stanzas", - XHTML_IM: "http://jabber.org/protocol/xhtml-im", - XHTML: "http://www.w3.org/1999/xhtml" + STANZAS: "urn:ietf:params:xml:ns:xmpp-stanzas" }, - - /** Constants: XHTML_IM Namespace - * contains allowed tags, tag attributes, and css properties. - * Used in the createHtml function to filter incoming html into the allowed XHTML-IM subset. - * See http://xmpp.org/extensions/xep-0071.html#profile-summary for the list of recommended - * allowed tags and their attributes. - */ - XHTML: { - tags: ['a','blockquote','br','cite','em','img','li','ol','p','span','strong','ul','body'], - attributes: { - 'a': ['href'], - 'blockquote': ['style'], - 'br': [], - 'cite': ['style'], - 'em': [], - 'img': ['src', 'alt', 'style', 'height', 'width'], - 'li': ['style'], - 'ol': ['style'], - 'p': ['style'], - 'span': ['style'], - 'strong': [], - 'ul': ['style'], - 'body': [] - }, - css: ['background-color','color','font-family','font-size','font-style','font-weight','margin-left','margin-right','text-align','text-decoration'], - validTag: function(tag) - { - for(var i = 0; i < Strophe.XHTML.tags.length; i++) { - if(tag == Strophe.XHTML.tags[i]) { - return true; - } - } - return false; - }, - validAttribute: function(tag, attribute) - { - if(typeof Strophe.XHTML.attributes[tag] !== 'undefined' && Strophe.XHTML.attributes[tag].length > 0) { - for(var i = 0; i < Strophe.XHTML.attributes[tag].length; i++) { - if(attribute == Strophe.XHTML.attributes[tag][i]) { - return true; - } - } - } - return false; - }, - validCSS: function(style) - { - for(var i = 0; i < Strophe.XHTML.css.length; i++) { - if(style == Strophe.XHTML.css[i]) { - return true; - } - } - return false; - } - }, - - /** Function: addNamespace + /** Function: addNamespace * This function is used to extend the current namespaces in * Strophe.NS. It takes a key and a value with the key being the * name of the new namespace, with its actual value. @@ -832,7 +565,7 @@ Strophe = { */ addNamespace: function (name, value) { - Strophe.NS[name] = value; + Strophe.NS[name] = value; }, /** Constants: Connection Status Constants @@ -883,13 +616,11 @@ Strophe = { * * ElementType.NORMAL - Normal element. * ElementType.TEXT - Text data element. - * ElementType.FRAGMENT - XHTML fragment element. */ ElementType: { NORMAL: 1, TEXT: 3, - CDATA: 4, - FRAGMENT: 11 + CDATA: 4 }, /** PrivateConstants: Timeout Values @@ -967,11 +698,7 @@ Strophe = { _makeGenerator: function () { var doc; - // IE9 does implement createDocument(); however, using it will cause the browser to leak memory on page unload. - // Here, we test for presence of createDocument() plus IE's proprietary documentMode attribute, which would be - // less than 10 in the case of IE9 and below. - if (document.implementation.createDocument === undefined || - document.implementation.createDocument && document.documentMode && document.documentMode < 10) { + if (document.implementation.createDocument === undefined) { doc = this._getIEXmlDom(); doc.appendChild(doc.createElement('strophe')); } else { @@ -1115,30 +842,10 @@ Strophe = { */ xmlTextNode: function (text) { - return Strophe.xmlGenerator().createTextNode(text); - }, + //ensure text is escaped + text = Strophe.xmlescape(text); - /** Function: xmlHtmlNode - * Creates an XML DOM html node. - * - * Parameters: - * (String) html - The content of the html node. - * - * Returns: - * A new XML DOM text node. - */ - xmlHtmlNode: function (html) - { - //ensure text is escaped - if (window.DOMParser) { - parser = new DOMParser(); - node = parser.parseFromString(html, "text/xml"); - } else { - node = new ActiveXObject("Microsoft.XMLDOM"); - node.async="false"; - node.loadXML(html); - } - return node; + return Strophe.xmlGenerator().createTextNode(text); }, /** Function: getText @@ -1166,7 +873,7 @@ Strophe = { } } - return Strophe.xmlescape(str); + return str; }, /** Function: copyElement @@ -1202,83 +909,6 @@ Strophe = { return el; }, - - /** Function: createHtml - * Copy an HTML DOM element into an XML DOM. - * - * This function copies a DOM element and all its descendants and returns - * the new copy. - * - * Parameters: - * (HTMLElement) elem - A DOM element. - * - * Returns: - * A new, copied DOM element tree. - */ - createHtml: function (elem) - { - var i, el, j, tag, attribute, value, css, cssAttrs, attr, cssName, cssValue, children, child; - if (elem.nodeType == Strophe.ElementType.NORMAL) { - tag = elem.nodeName.toLowerCase(); - if(Strophe.XHTML.validTag(tag)) { - try { - el = Strophe.xmlElement(tag); - for(i = 0; i < Strophe.XHTML.attributes[tag].length; i++) { - attribute = Strophe.XHTML.attributes[tag][i]; - value = elem.getAttribute(attribute); - if(typeof value == 'undefined' || value === null || value === '' || value === false || value === 0) { - continue; - } - if(attribute == 'style' && typeof value == 'object') { - if(typeof value.cssText != 'undefined') { - value = value.cssText; // we're dealing with IE, need to get CSS out - } - } - // filter out invalid css styles - if(attribute == 'style') { - css = []; - cssAttrs = value.split(';'); - for(j = 0; j < cssAttrs.length; j++) { - attr = cssAttrs[j].split(':'); - cssName = attr[0].replace(/^\s*/, "").replace(/\s*$/, "").toLowerCase(); - if(Strophe.XHTML.validCSS(cssName)) { - cssValue = attr[1].replace(/^\s*/, "").replace(/\s*$/, ""); - css.push(cssName + ': ' + cssValue); - } - } - if(css.length > 0) { - value = css.join('; '); - el.setAttribute(attribute, value); - } - } else { - el.setAttribute(attribute, value); - } - } - - for (i = 0; i < elem.childNodes.length; i++) { - el.appendChild(Strophe.createHtml(elem.childNodes[i])); - } - } catch(e) { // invalid elements - el = Strophe.xmlTextNode(''); - } - } else { - el = Strophe.xmlGenerator().createDocumentFragment(); - for (i = 0; i < elem.childNodes.length; i++) { - el.appendChild(Strophe.createHtml(elem.childNodes[i])); - } - } - } else if (elem.nodeType == Strophe.ElementType.FRAGMENT) { - el = Strophe.xmlGenerator().createDocumentFragment(); - for (i = 0; i < elem.childNodes.length; i++) { - el.appendChild(Strophe.createHtml(elem.childNodes[i])); - } - } else if (elem.nodeType == Strophe.ElementType.TEXT) { - el = Strophe.xmlTextNode(elem.nodeValue); - } - - return el; - }, - /** Function: escapeNode * Escape the node part (also called local part) of a JID. * @@ -1515,7 +1145,6 @@ Strophe = { "='" + elem.attributes[i].value .replace(/&/g, "&") .replace(/\'/g, "'") - .replace(/>/g, ">") .replace(/ 0) { - this.node.appendChild(xhtml.childNodes[0]); - } - return this; } }; + /** PrivateClass: Strophe.Handler * _Private_ helper class for managing stanza handlers. * @@ -1839,7 +1442,7 @@ Strophe.Handler = function (handler, ns, name, type, id, from, options) this.type = type; this.id = id; this.options = options || {matchbare: false}; - + // default matchBare to false if undefined if (!this.options.matchBare) { this.options.matchBare = false; @@ -1869,7 +1472,7 @@ Strophe.Handler.prototype = { { var nsMatch; var from = null; - + if (this.options.matchBare) { from = Strophe.getBareJidFromJid(elem.getAttribute('from')); } else { @@ -1930,7 +1533,7 @@ Strophe.Handler.prototype = { e.fileName + ":" + e.lineNumber + " - " + e.name + ": " + e.message); } else { - Strophe.fatal("error: " + e.message + "\n" + e.stack); + Strophe.fatal("error: " + this.handler); } throw e; @@ -2131,7 +1734,7 @@ Strophe.Request.prototype = { /** Class: Strophe.Connection * XMPP Connection manager. * - * This class is the main part of Strophe. It manages a BOSH connection + * Thie class is the main part of Strophe. It manages a BOSH connection * to an XMPP server and dispatches events to the user callbacks as * data arrives. It supports SASL PLAIN, SASL DIGEST-MD5, and legacy * authentication. @@ -2165,8 +1768,6 @@ Strophe.Connection = function (service) this.service = service; /* The connected JID. */ this.jid = ""; - /* the JIDs domain */ - this.domain = null; /* request id for body tags */ this.rid = Math.floor(Math.random() * 4294967295); /* The current session ID. */ @@ -2176,7 +1777,6 @@ Strophe.Connection = function (service) this.features = null; // SASL - this._sasl_data = []; this.do_session = false; this.do_bind = false; @@ -2188,11 +1788,9 @@ Strophe.Connection = function (service) this.addTimeds = []; this.addHandlers = []; - this._authentication = {}; this._idleTimeout = null; this._disconnectTimeout = null; - this.do_authentication = true; this.authenticated = false; this.disconnecting = false; this.connected = false; @@ -2214,9 +1812,6 @@ Strophe.Connection = function (service) this._sasl_failure_handler = null; this._sasl_challenge_handler = null; - // Max retries before disconnecting - this.maxRetries = 5; - // setup onIdle callback every 1/10th of a second this._idleTimeout = setTimeout(this._onIdle.bind(this), 100); @@ -2258,7 +1853,6 @@ Strophe.Connection.prototype = { this.removeHandlers = []; this.addTimeds = []; this.addHandlers = []; - this._authentication = {}; this.authenticated = false; this.disconnecting = false; @@ -2347,12 +1941,12 @@ Strophe.Connection.prototype = { * (Integer) wait - The optional HTTPBIND wait value. This is the * time the server will wait before returning an empty result for * a request. The default setting of 60 seconds is recommended. + * Other settings will require tweaks to the Strophe.TIMEOUT value. * (Integer) hold - The optional HTTPBIND hold value. This is the * number of connections the server will hold at one time. This * should almost always be set to 1 (the default). - * (String) route */ - connect: function (jid, pass, callback, wait, hold, route) + connect: function (jid, pass, callback, wait, hold) { this.jid = jid; this.pass = pass; @@ -2366,7 +1960,7 @@ Strophe.Connection.prototype = { this.hold = hold || this.hold; // parse jid for domain and resource - this.domain = this.domain || Strophe.getDomainFromJid(this.jid); + this.domain = Strophe.getDomainFromJid(this.jid); // build the body tag var body = this._buildBody().attrs({ @@ -2380,21 +1974,12 @@ Strophe.Connection.prototype = { "xmlns:xmpp": Strophe.NS.BOSH }); - if(route){ - body.attrs({ - route: route - }); - } - this._changeConnectStatus(Strophe.Status.CONNECTING, null); - var _connect_cb = this._connect_callback || this._connect_cb; - this._connect_callback = null; - this._requests.push( new Strophe.Request(body.tree(), this._onRequestStateChange.bind( - this, _connect_cb.bind(this)), + this, this._connect_cb.bind(this)), body.tree().getAttribute("rid"))); this._throttledRequestHandler(); }, @@ -2640,7 +2225,7 @@ Strophe.Connection.prototype = { message: "Cannot queue non-DOMElement." }; } - + this._data.push(element); }, @@ -2915,7 +2500,7 @@ Strophe.Connection.prototype = { } // make sure we limit the number of retries - if (req.sends > this.maxRetries) { + if (req.sends > 5) { this._onDisconnectTimeout(); return; } @@ -3319,11 +2904,8 @@ Strophe.Connection.prototype = { * * Parameters: * (Strophe.Request) req - The current request. - * (Function) _callback - low level (xmpp) connect callback function. - * Useful for plugins with their own xmpp connect callback (when their) - * want to do something special). */ - _connect_cb: function (req, _callback) + _connect_cb: function (req) { Strophe.info("_connect_cb was called"); @@ -3370,74 +2952,39 @@ Strophe.Connection.prototype = { var wait = bodyWrap.getAttribute('wait'); if (wait) { this.wait = parseInt(wait, 10); } - this._authentication.sasl_scram_sha1 = false; - this._authentication.sasl_plain = false; - this._authentication.sasl_digest_md5 = false; - this._authentication.sasl_anonymous = false; - this._authentication.legacy_auth = false; + var do_sasl_plain = false; + var do_sasl_digest_md5 = false; + var do_sasl_anonymous = false; - // Check for the stream:features tag - var hasFeatures = bodyWrap.getElementsByTagName("stream:features").length > 0; - if (!hasFeatures) { - hasFeatures = bodyWrap.getElementsByTagName("features").length > 0; - } var mechanisms = bodyWrap.getElementsByTagName("mechanism"); - var i, mech, auth_str, hashed_auth_str, - found_authentication = false; - if (hasFeatures && mechanisms.length > 0) { - var missmatchedmechs = 0; + var i, mech, auth_str, hashed_auth_str; + if (mechanisms.length > 0) { for (i = 0; i < mechanisms.length; i++) { mech = Strophe.getText(mechanisms[i]); - if (mech == 'SCRAM-SHA-1') { - this._authentication.sasl_scram_sha1 = true; - } else if (mech == 'DIGEST-MD5') { - this._authentication.sasl_digest_md5 = true; + if (mech == 'DIGEST-MD5') { + do_sasl_digest_md5 = true; } else if (mech == 'PLAIN') { - this._authentication.sasl_plain = true; + do_sasl_plain = true; } else if (mech == 'ANONYMOUS') { - this._authentication.sasl_anonymous = true; - } else missmatchedmechs++; + do_sasl_anonymous = true; + } } - - this._authentication.legacy_auth = - bodyWrap.getElementsByTagName("auth").length > 0; - - found_authentication = - this._authentication.legacy_auth || - missmatchedmechs < mechanisms.length; - } - if (!found_authentication) { - _callback = _callback || this._connect_cb; + } else { // we didn't get stream:features yet, so we need wait for it // by sending a blank poll request var body = this._buildBody(); this._requests.push( new Strophe.Request(body.tree(), this._onRequestStateChange.bind( - this, _callback.bind(this)), + this, this._connect_cb.bind(this)), body.tree().getAttribute("rid"))); this._throttledRequestHandler(); return; } - if (this.do_authentication !== false) - this.authenticate(); - }, - /** Function: authenticate - * Set up authentication - * - * Contiunues the initial connection request by setting up authentication - * handlers and start the authentication process. - * - * SASL authentication will be attempted if available, otherwise - * the code will fall back to legacy authentication. - * - */ - authenticate: function () - { if (Strophe.getNodeFromJid(this.jid) === null && - this._authentication.sasl_anonymous) { + do_sasl_anonymous) { this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null); this._sasl_success_handler = this._addSysHandler( this._sasl_success_cb.bind(this), null, @@ -3456,34 +3003,10 @@ Strophe.Connection.prototype = { this._changeConnectStatus(Strophe.Status.CONNFAIL, 'x-strophe-bad-non-anon-jid'); this.disconnect(); - } else if (this._authentication.sasl_scram_sha1) { - var cnonce = MD5.hexdigest(Math.random() * 1234567890); - - var auth_str = "n=" + Strophe.getNodeFromJid(this.jid); - auth_str += ",r="; - auth_str += cnonce; - - this._sasl_data["cnonce"] = cnonce; - this._sasl_data["client-first-message-bare"] = auth_str; - - auth_str = "n,," + auth_str; - - this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null); - this._sasl_challenge_handler = this._addSysHandler( - this._sasl_scram_challenge_cb.bind(this), null, - "challenge", null, null); - this._sasl_failure_handler = this._addSysHandler( - this._sasl_failure_cb.bind(this), null, - "failure", null, null); - - this.send($build("auth", { - xmlns: Strophe.NS.SASL, - mechanism: "SCRAM-SHA-1" - }).t(Base64.encode(auth_str)).tree()); - } else if (this._authentication.sasl_digest_md5) { + } else if (do_sasl_digest_md5) { this._changeConnectStatus(Strophe.Status.AUTHENTICATING, null); this._sasl_challenge_handler = this._addSysHandler( - this._sasl_digest_challenge1_cb.bind(this), null, + this._sasl_challenge1_cb.bind(this), null, "challenge", null, null); this._sasl_failure_handler = this._addSysHandler( this._sasl_failure_cb.bind(this), null, @@ -3493,7 +3016,7 @@ Strophe.Connection.prototype = { xmlns: Strophe.NS.SASL, mechanism: "DIGEST-MD5" }).tree()); - } else if (this._authentication.sasl_plain) { + } else if (do_sasl_plain) { // Build the plain auth string (barejid null // username null password) and base 64 encoded. auth_str = Strophe.getBareJidFromJid(this.jid); @@ -3530,7 +3053,7 @@ Strophe.Connection.prototype = { } }, - /** PrivateFunction: _sasl_digest_challenge1_cb + /** PrivateFunction: _sasl_challenge1_cb * _Private_ handler for DIGEST-MD5 SASL authentication. * * Parameters: @@ -3539,7 +3062,7 @@ Strophe.Connection.prototype = { * Returns: * false to remove the handler. */ - _sasl_digest_challenge1_cb: function (elem) + _sasl_challenge1_cb: function (elem) { var attribMatch = /([a-z]+)=("[^"]+"|[^,"]+)(?:,|$)/; @@ -3601,7 +3124,7 @@ Strophe.Connection.prototype = { responseText += 'charset="utf-8"'; this._sasl_challenge_handler = this._addSysHandler( - this._sasl_digest_challenge2_cb.bind(this), null, + this._sasl_challenge2_cb.bind(this), null, "challenge", null, null); this._sasl_success_handler = this._addSysHandler( this._sasl_success_cb.bind(this), null, @@ -3633,7 +3156,7 @@ Strophe.Connection.prototype = { }, - /** PrivateFunction: _sasl_digest_challenge2_cb + /** PrivateFunction: _sasl_challenge2_cb * _Private_ handler for second step of DIGEST-MD5 SASL authentication. * * Parameters: @@ -3642,7 +3165,7 @@ Strophe.Connection.prototype = { * Returns: * false to remove the handler. */ - _sasl_digest_challenge2_cb: function (elem) + _sasl_challenge2_cb: function (elem) { // remove unneeded handlers this.deleteHandler(this._sasl_success_handler); @@ -3658,91 +3181,6 @@ Strophe.Connection.prototype = { return false; }, - /** PrivateFunction: _sasl_scram_challenge_cb - * _Private_ handler for SCRAM-SHA-1 SASL authentication. - * - * Parameters: - * (XMLElement) elem - The challenge stanza. - * - * Returns: - * false to remove the handler. - */ - _sasl_scram_challenge_cb: function (elem) - { - var nonce, salt, iter, Hi, U, U_old; - var clientKey, serverKey, clientSignature; - var responseText = "c=biws,"; - var challenge = Base64.decode(Strophe.getText(elem)); - var authMessage = this._sasl_data["client-first-message-bare"] + "," + - challenge + ","; - var cnonce = this._sasl_data["cnonce"] - var attribMatch = /([a-z]+)=([^,]+)(,|$)/; - - // remove unneeded handlers - this.deleteHandler(this._sasl_failure_handler); - - while (challenge.match(attribMatch)) { - matches = challenge.match(attribMatch); - challenge = challenge.replace(matches[0], ""); - switch (matches[1]) { - case "r": - nonce = matches[2]; - break; - case "s": - salt = matches[2]; - break; - case "i": - iter = matches[2]; - break; - } - } - - if (!(nonce.substr(0, cnonce.length) === cnonce)) { - this._sasl_data = []; - return this._sasl_failure_cb(null); - } - - responseText += "r=" + nonce; - authMessage += responseText; - - salt = Base64.decode(salt); - salt += "\0\0\0\1"; - - Hi = U_old = core_hmac_sha1(this.pass, salt); - for (i = 1; i < iter; i++) { - U = core_hmac_sha1(this.pass, binb2str(U_old)); - for (k = 0; k < 5; k++) { - Hi[k] ^= U[k]; - } - U_old = U; - } - Hi = binb2str(Hi); - - clientKey = core_hmac_sha1(Hi, "Client Key"); - serverKey = str_hmac_sha1(Hi, "Server Key"); - clientSignature = core_hmac_sha1(str_sha1(binb2str(clientKey)), authMessage); - this._sasl_data["server-signature"] = b64_hmac_sha1(serverKey, authMessage); - - for (k = 0; k < 5; k++) { - clientKey[k] ^= clientSignature[k]; - } - - responseText += ",p=" + Base64.encode(binb2str(clientKey)); - - this._sasl_success_handler = this._addSysHandler( - this._sasl_success_cb.bind(this), null, - "success", null, null); - this._sasl_failure_handler = this._addSysHandler( - this._sasl_failure_cb.bind(this), null, - "failure", null, null); - - this.send($build('response', { - xmlns: Strophe.NS.SASL - }).t(Base64.encode(responseText)).tree()); - - return false; - }, - /** PrivateFunction: _auth1_cb * _Private_ handler for legacy authentication. * @@ -3793,29 +3231,7 @@ Strophe.Connection.prototype = { */ _sasl_success_cb: function (elem) { - if (this._sasl_data["server-signature"]) { - var serverSignature; - var success = Base64.decode(Strophe.getText(elem)); - var attribMatch = /([a-z]+)=([^,]+)(,|$)/; - matches = success.match(attribMatch); - if (matches[1] == "v") { - serverSignature = matches[2]; - } - if (serverSignature != this._sasl_data["server-signature"]) { - // remove old handlers - this.deleteHandler(this._sasl_failure_handler); - this._sasl_failure_handler = null; - if (this._sasl_challenge_handler) { - this.deleteHandler(this._sasl_challenge_handler); - this._sasl_challenge_handler = null; - } - - this._sasl_data = []; - return this._sasl_failure_cb(null); - } - } - - Strophe.info("SASL authentication succeeded."); + Strophe.info("SASL authentication succeeded."); // remove old handlers this.deleteHandler(this._sasl_failure_handler); @@ -3896,11 +3312,7 @@ Strophe.Connection.prototype = { { if (elem.getAttribute("type") == "error") { Strophe.info("SASL binding failed."); - var conflict = elem.getElementsByTagName("conflict"), condition; - if (conflict.length > 0) { - condition = 'conflict'; - } - this._changeConnectStatus(Strophe.Status.AUTHFAIL, condition); + this._changeConnectStatus(Strophe.Status.AUTHFAIL, null); return false; } diff --git a/labs/architecture-examples/backbone.xmpp/bower_components/backbone/backbone.js b/labs/architecture-examples/backbone.xmpp/bower_components/backbone/backbone.js new file mode 100644 index 0000000000..3512d42fb4 --- /dev/null +++ b/labs/architecture-examples/backbone.xmpp/bower_components/backbone/backbone.js @@ -0,0 +1,1571 @@ +// Backbone.js 1.0.0 + +// (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc. +// Backbone may be freely distributed under the MIT license. +// For all details and documentation: +// http://backbonejs.org + +(function(){ + + // Initial Setup + // ------------- + + // Save a reference to the global object (`window` in the browser, `exports` + // on the server). + var root = this; + + // Save the previous value of the `Backbone` variable, so that it can be + // restored later on, if `noConflict` is used. + var previousBackbone = root.Backbone; + + // Create local references to array methods we'll want to use later. + var array = []; + var push = array.push; + var slice = array.slice; + var splice = array.splice; + + // The top-level namespace. All public Backbone classes and modules will + // be attached to this. Exported for both the browser and the server. + var Backbone; + if (typeof exports !== 'undefined') { + Backbone = exports; + } else { + Backbone = root.Backbone = {}; + } + + // Current version of the library. Keep in sync with `package.json`. + Backbone.VERSION = '1.0.0'; + + // Require Underscore, if we're on the server, and it's not already present. + var _ = root._; + if (!_ && (typeof require !== 'undefined')) _ = require('underscore'); + + // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns + // the `$` variable. + Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$; + + // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable + // to its previous owner. Returns a reference to this Backbone object. + Backbone.noConflict = function() { + root.Backbone = previousBackbone; + return this; + }; + + // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option + // will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and + // set a `X-Http-Method-Override` header. + Backbone.emulateHTTP = false; + + // Turn on `emulateJSON` to support legacy servers that can't deal with direct + // `application/json` requests ... will encode the body as + // `application/x-www-form-urlencoded` instead and will send the model in a + // form param named `model`. + Backbone.emulateJSON = false; + + // Backbone.Events + // --------------- + + // A module that can be mixed in to *any object* in order to provide it with + // custom events. You may bind with `on` or remove with `off` callback + // functions to an event; `trigger`-ing an event fires all callbacks in + // succession. + // + // var object = {}; + // _.extend(object, Backbone.Events); + // object.on('expand', function(){ alert('expanded'); }); + // object.trigger('expand'); + // + var Events = Backbone.Events = { + + // Bind an event to a `callback` function. Passing `"all"` will bind + // the callback to all events fired. + on: function(name, callback, context) { + if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this; + this._events || (this._events = {}); + var events = this._events[name] || (this._events[name] = []); + events.push({callback: callback, context: context, ctx: context || this}); + return this; + }, + + // Bind an event to only be triggered a single time. After the first time + // the callback is invoked, it will be removed. + once: function(name, callback, context) { + if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this; + var self = this; + var once = _.once(function() { + self.off(name, once); + callback.apply(this, arguments); + }); + once._callback = callback; + return this.on(name, once, context); + }, + + // Remove one or many callbacks. If `context` is null, removes all + // callbacks with that function. If `callback` is null, removes all + // callbacks for the event. If `name` is null, removes all bound + // callbacks for all events. + off: function(name, callback, context) { + var retain, ev, events, names, i, l, j, k; + if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; + if (!name && !callback && !context) { + this._events = {}; + return this; + } + + names = name ? [name] : _.keys(this._events); + for (i = 0, l = names.length; i < l; i++) { + name = names[i]; + if (events = this._events[name]) { + this._events[name] = retain = []; + if (callback || context) { + for (j = 0, k = events.length; j < k; j++) { + ev = events[j]; + if ((callback && callback !== ev.callback && callback !== ev.callback._callback) || + (context && context !== ev.context)) { + retain.push(ev); + } + } + } + if (!retain.length) delete this._events[name]; + } + } + + return this; + }, + + // Trigger one or many events, firing all bound callbacks. Callbacks are + // passed the same arguments as `trigger` is, apart from the event name + // (unless you're listening on `"all"`, which will cause your callback to + // receive the true name of the event as the first argument). + trigger: function(name) { + if (!this._events) return this; + var args = slice.call(arguments, 1); + if (!eventsApi(this, 'trigger', name, args)) return this; + var events = this._events[name]; + var allEvents = this._events.all; + if (events) triggerEvents(events, args); + if (allEvents) triggerEvents(allEvents, arguments); + return this; + }, + + // Tell this object to stop listening to either specific events ... or + // to every object it's currently listening to. + stopListening: function(obj, name, callback) { + var listeners = this._listeners; + if (!listeners) return this; + var deleteListener = !name && !callback; + if (typeof name === 'object') callback = this; + if (obj) (listeners = {})[obj._listenerId] = obj; + for (var id in listeners) { + listeners[id].off(name, callback, this); + if (deleteListener) delete this._listeners[id]; + } + return this; + } + + }; + + // Regular expression used to split event strings. + var eventSplitter = /\s+/; + + // Implement fancy features of the Events API such as multiple event + // names `"change blur"` and jQuery-style event maps `{change: action}` + // in terms of the existing API. + var eventsApi = function(obj, action, name, rest) { + if (!name) return true; + + // Handle event maps. + if (typeof name === 'object') { + for (var key in name) { + obj[action].apply(obj, [key, name[key]].concat(rest)); + } + return false; + } + + // Handle space separated event names. + if (eventSplitter.test(name)) { + var names = name.split(eventSplitter); + for (var i = 0, l = names.length; i < l; i++) { + obj[action].apply(obj, [names[i]].concat(rest)); + } + return false; + } + + return true; + }; + + // A difficult-to-believe, but optimized internal dispatch function for + // triggering events. Tries to keep the usual cases speedy (most internal + // Backbone events have 3 arguments). + var triggerEvents = function(events, args) { + var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; + switch (args.length) { + case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; + case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; + case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; + case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; + default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); + } + }; + + var listenMethods = {listenTo: 'on', listenToOnce: 'once'}; + + // Inversion-of-control versions of `on` and `once`. Tell *this* object to + // listen to an event in another object ... keeping track of what it's + // listening to. + _.each(listenMethods, function(implementation, method) { + Events[method] = function(obj, name, callback) { + var listeners = this._listeners || (this._listeners = {}); + var id = obj._listenerId || (obj._listenerId = _.uniqueId('l')); + listeners[id] = obj; + if (typeof name === 'object') callback = this; + obj[implementation](name, callback, this); + return this; + }; + }); + + // Aliases for backwards compatibility. + Events.bind = Events.on; + Events.unbind = Events.off; + + // Allow the `Backbone` object to serve as a global event bus, for folks who + // want global "pubsub" in a convenient place. + _.extend(Backbone, Events); + + // Backbone.Model + // -------------- + + // Backbone **Models** are the basic data object in the framework -- + // frequently representing a row in a table in a database on your server. + // A discrete chunk of data and a bunch of useful, related methods for + // performing computations and transformations on that data. + + // Create a new model with the specified attributes. A client id (`cid`) + // is automatically generated and assigned for you. + var Model = Backbone.Model = function(attributes, options) { + var defaults; + var attrs = attributes || {}; + options || (options = {}); + this.cid = _.uniqueId('c'); + this.attributes = {}; + _.extend(this, _.pick(options, modelOptions)); + if (options.parse) attrs = this.parse(attrs, options) || {}; + if (defaults = _.result(this, 'defaults')) { + attrs = _.defaults({}, attrs, defaults); + } + this.set(attrs, options); + this.changed = {}; + this.initialize.apply(this, arguments); + }; + + // A list of options to be attached directly to the model, if provided. + var modelOptions = ['url', 'urlRoot', 'collection']; + + // Attach all inheritable methods to the Model prototype. + _.extend(Model.prototype, Events, { + + // A hash of attributes whose current and previous value differ. + changed: null, + + // The value returned during the last failed validation. + validationError: null, + + // The default name for the JSON `id` attribute is `"id"`. MongoDB and + // CouchDB users may want to set this to `"_id"`. + idAttribute: 'id', + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // Return a copy of the model's `attributes` object. + toJSON: function(options) { + return _.clone(this.attributes); + }, + + // Proxy `Backbone.sync` by default -- but override this if you need + // custom syncing semantics for *this* particular model. + sync: function() { + return Backbone.sync.apply(this, arguments); + }, + + // Get the value of an attribute. + get: function(attr) { + return this.attributes[attr]; + }, + + // Get the HTML-escaped value of an attribute. + escape: function(attr) { + return _.escape(this.get(attr)); + }, + + // Returns `true` if the attribute contains a value that is not null + // or undefined. + has: function(attr) { + return this.get(attr) != null; + }, + + // Set a hash of model attributes on the object, firing `"change"`. This is + // the core primitive operation of a model, updating the data and notifying + // anyone who needs to know about the change in state. The heart of the beast. + set: function(key, val, options) { + var attr, attrs, unset, changes, silent, changing, prev, current; + if (key == null) return this; + + // Handle both `"key", value` and `{key: value}` -style arguments. + if (typeof key === 'object') { + attrs = key; + options = val; + } else { + (attrs = {})[key] = val; + } + + options || (options = {}); + + // Run validation. + if (!this._validate(attrs, options)) return false; + + // Extract attributes and options. + unset = options.unset; + silent = options.silent; + changes = []; + changing = this._changing; + this._changing = true; + + if (!changing) { + this._previousAttributes = _.clone(this.attributes); + this.changed = {}; + } + current = this.attributes, prev = this._previousAttributes; + + // Check for changes of `id`. + if (this.idAttribute in attrs) this.id = attrs[this.idAttribute]; + + // For each `set` attribute, update or delete the current value. + for (attr in attrs) { + val = attrs[attr]; + if (!_.isEqual(current[attr], val)) changes.push(attr); + if (!_.isEqual(prev[attr], val)) { + this.changed[attr] = val; + } else { + delete this.changed[attr]; + } + unset ? delete current[attr] : current[attr] = val; + } + + // Trigger all relevant attribute changes. + if (!silent) { + if (changes.length) this._pending = true; + for (var i = 0, l = changes.length; i < l; i++) { + this.trigger('change:' + changes[i], this, current[changes[i]], options); + } + } + + // You might be wondering why there's a `while` loop here. Changes can + // be recursively nested within `"change"` events. + if (changing) return this; + if (!silent) { + while (this._pending) { + this._pending = false; + this.trigger('change', this, options); + } + } + this._pending = false; + this._changing = false; + return this; + }, + + // Remove an attribute from the model, firing `"change"`. `unset` is a noop + // if the attribute doesn't exist. + unset: function(attr, options) { + return this.set(attr, void 0, _.extend({}, options, {unset: true})); + }, + + // Clear all attributes on the model, firing `"change"`. + clear: function(options) { + var attrs = {}; + for (var key in this.attributes) attrs[key] = void 0; + return this.set(attrs, _.extend({}, options, {unset: true})); + }, + + // Determine if the model has changed since the last `"change"` event. + // If you specify an attribute name, determine if that attribute has changed. + hasChanged: function(attr) { + if (attr == null) return !_.isEmpty(this.changed); + return _.has(this.changed, attr); + }, + + // Return an object containing all the attributes that have changed, or + // false if there are no changed attributes. Useful for determining what + // parts of a view need to be updated and/or what attributes need to be + // persisted to the server. Unset attributes will be set to undefined. + // You can also pass an attributes object to diff against the model, + // determining if there *would be* a change. + changedAttributes: function(diff) { + if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; + var val, changed = false; + var old = this._changing ? this._previousAttributes : this.attributes; + for (var attr in diff) { + if (_.isEqual(old[attr], (val = diff[attr]))) continue; + (changed || (changed = {}))[attr] = val; + } + return changed; + }, + + // Get the previous value of an attribute, recorded at the time the last + // `"change"` event was fired. + previous: function(attr) { + if (attr == null || !this._previousAttributes) return null; + return this._previousAttributes[attr]; + }, + + // Get all of the attributes of the model at the time of the previous + // `"change"` event. + previousAttributes: function() { + return _.clone(this._previousAttributes); + }, + + // Fetch the model from the server. If the server's representation of the + // model differs from its current attributes, they will be overridden, + // triggering a `"change"` event. + fetch: function(options) { + options = options ? _.clone(options) : {}; + if (options.parse === void 0) options.parse = true; + var model = this; + var success = options.success; + options.success = function(resp) { + if (!model.set(model.parse(resp, options), options)) return false; + if (success) success(model, resp, options); + model.trigger('sync', model, resp, options); + }; + wrapError(this, options); + return this.sync('read', this, options); + }, + + // Set a hash of model attributes, and sync the model to the server. + // If the server returns an attributes hash that differs, the model's + // state will be `set` again. + save: function(key, val, options) { + var attrs, method, xhr, attributes = this.attributes; + + // Handle both `"key", value` and `{key: value}` -style arguments. + if (key == null || typeof key === 'object') { + attrs = key; + options = val; + } else { + (attrs = {})[key] = val; + } + + // If we're not waiting and attributes exist, save acts as `set(attr).save(null, opts)`. + if (attrs && (!options || !options.wait) && !this.set(attrs, options)) return false; + + options = _.extend({validate: true}, options); + + // Do not persist invalid models. + if (!this._validate(attrs, options)) return false; + + // Set temporary attributes if `{wait: true}`. + if (attrs && options.wait) { + this.attributes = _.extend({}, attributes, attrs); + } + + // After a successful server-side save, the client is (optionally) + // updated with the server-side state. + if (options.parse === void 0) options.parse = true; + var model = this; + var success = options.success; + options.success = function(resp) { + // Ensure attributes are restored during synchronous saves. + model.attributes = attributes; + var serverAttrs = model.parse(resp, options); + if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs); + if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) { + return false; + } + if (success) success(model, resp, options); + model.trigger('sync', model, resp, options); + }; + wrapError(this, options); + + method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update'); + if (method === 'patch') options.attrs = attrs; + xhr = this.sync(method, this, options); + + // Restore attributes. + if (attrs && options.wait) this.attributes = attributes; + + return xhr; + }, + + // Destroy this model on the server if it was already persisted. + // Optimistically removes the model from its collection, if it has one. + // If `wait: true` is passed, waits for the server to respond before removal. + destroy: function(options) { + options = options ? _.clone(options) : {}; + var model = this; + var success = options.success; + + var destroy = function() { + model.trigger('destroy', model, model.collection, options); + }; + + options.success = function(resp) { + if (options.wait || model.isNew()) destroy(); + if (success) success(model, resp, options); + if (!model.isNew()) model.trigger('sync', model, resp, options); + }; + + if (this.isNew()) { + options.success(); + return false; + } + wrapError(this, options); + + var xhr = this.sync('delete', this, options); + if (!options.wait) destroy(); + return xhr; + }, + + // Default URL for the model's representation on the server -- if you're + // using Backbone's restful methods, override this to change the endpoint + // that will be called. + url: function() { + var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError(); + if (this.isNew()) return base; + return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id); + }, + + // **parse** converts a response into the hash of attributes to be `set` on + // the model. The default implementation is just to pass the response along. + parse: function(resp, options) { + return resp; + }, + + // Create a new model with identical attributes to this one. + clone: function() { + return new this.constructor(this.attributes); + }, + + // A model is new if it has never been saved to the server, and lacks an id. + isNew: function() { + return this.id == null; + }, + + // Check if the model is currently in a valid state. + isValid: function(options) { + return this._validate({}, _.extend(options || {}, { validate: true })); + }, + + // Run validation against the next complete set of model attributes, + // returning `true` if all is well. Otherwise, fire an `"invalid"` event. + _validate: function(attrs, options) { + if (!options.validate || !this.validate) return true; + attrs = _.extend({}, this.attributes, attrs); + var error = this.validationError = this.validate(attrs, options) || null; + if (!error) return true; + this.trigger('invalid', this, error, _.extend(options || {}, {validationError: error})); + return false; + } + + }); + + // Underscore methods that we want to implement on the Model. + var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit']; + + // Mix in each Underscore method as a proxy to `Model#attributes`. + _.each(modelMethods, function(method) { + Model.prototype[method] = function() { + var args = slice.call(arguments); + args.unshift(this.attributes); + return _[method].apply(_, args); + }; + }); + + // Backbone.Collection + // ------------------- + + // If models tend to represent a single row of data, a Backbone Collection is + // more analagous to a table full of data ... or a small slice or page of that + // table, or a collection of rows that belong together for a particular reason + // -- all of the messages in this particular folder, all of the documents + // belonging to this particular author, and so on. Collections maintain + // indexes of their models, both in order, and for lookup by `id`. + + // Create a new **Collection**, perhaps to contain a specific type of `model`. + // If a `comparator` is specified, the Collection will maintain + // its models in sort order, as they're added and removed. + var Collection = Backbone.Collection = function(models, options) { + options || (options = {}); + if (options.url) this.url = options.url; + if (options.model) this.model = options.model; + if (options.comparator !== void 0) this.comparator = options.comparator; + this._reset(); + this.initialize.apply(this, arguments); + if (models) this.reset(models, _.extend({silent: true}, options)); + }; + + // Default options for `Collection#set`. + var setOptions = {add: true, remove: true, merge: true}; + var addOptions = {add: true, merge: false, remove: false}; + + // Define the Collection's inheritable methods. + _.extend(Collection.prototype, Events, { + + // The default model for a collection is just a **Backbone.Model**. + // This should be overridden in most cases. + model: Model, + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // The JSON representation of a Collection is an array of the + // models' attributes. + toJSON: function(options) { + return this.map(function(model){ return model.toJSON(options); }); + }, + + // Proxy `Backbone.sync` by default. + sync: function() { + return Backbone.sync.apply(this, arguments); + }, + + // Add a model, or list of models to the set. + add: function(models, options) { + return this.set(models, _.defaults(options || {}, addOptions)); + }, + + // Remove a model, or a list of models from the set. + remove: function(models, options) { + models = _.isArray(models) ? models.slice() : [models]; + options || (options = {}); + var i, l, index, model; + for (i = 0, l = models.length; i < l; i++) { + model = this.get(models[i]); + if (!model) continue; + delete this._byId[model.id]; + delete this._byId[model.cid]; + index = this.indexOf(model); + this.models.splice(index, 1); + this.length--; + if (!options.silent) { + options.index = index; + model.trigger('remove', model, this, options); + } + this._removeReference(model); + } + return this; + }, + + // Update a collection by `set`-ing a new list of models, adding new ones, + // removing models that are no longer present, and merging models that + // already exist in the collection, as necessary. Similar to **Model#set**, + // the core operation for updating the data contained by the collection. + set: function(models, options) { + options = _.defaults(options || {}, setOptions); + if (options.parse) models = this.parse(models, options); + if (!_.isArray(models)) models = models ? [models] : []; + var i, l, model, attrs, existing, sort; + var at = options.at; + var sortable = this.comparator && (at == null) && options.sort !== false; + var sortAttr = _.isString(this.comparator) ? this.comparator : null; + var toAdd = [], toRemove = [], modelMap = {}; + + // Turn bare objects into model references, and prevent invalid models + // from being added. + for (i = 0, l = models.length; i < l; i++) { + if (!(model = this._prepareModel(models[i], options))) continue; + + // If a duplicate is found, prevent it from being added and + // optionally merge it into the existing model. + if (existing = this.get(model)) { + if (options.remove) modelMap[existing.cid] = true; + if (options.merge) { + existing.set(model.attributes, options); + if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true; + } + + // This is a new model, push it to the `toAdd` list. + } else if (options.add) { + toAdd.push(model); + + // Listen to added models' events, and index models for lookup by + // `id` and by `cid`. + model.on('all', this._onModelEvent, this); + this._byId[model.cid] = model; + if (model.id != null) this._byId[model.id] = model; + } + } + + // Remove nonexistent models if appropriate. + if (options.remove) { + for (i = 0, l = this.length; i < l; ++i) { + if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model); + } + if (toRemove.length) this.remove(toRemove, options); + } + + // See if sorting is needed, update `length` and splice in new models. + if (toAdd.length) { + if (sortable) sort = true; + this.length += toAdd.length; + if (at != null) { + splice.apply(this.models, [at, 0].concat(toAdd)); + } else { + push.apply(this.models, toAdd); + } + } + + // Silently sort the collection if appropriate. + if (sort) this.sort({silent: true}); + + if (options.silent) return this; + + // Trigger `add` events. + for (i = 0, l = toAdd.length; i < l; i++) { + (model = toAdd[i]).trigger('add', model, this, options); + } + + // Trigger `sort` if the collection was sorted. + if (sort) this.trigger('sort', this, options); + return this; + }, + + // When you have more items than you want to add or remove individually, + // you can reset the entire set with a new list of models, without firing + // any granular `add` or `remove` events. Fires `reset` when finished. + // Useful for bulk operations and optimizations. + reset: function(models, options) { + options || (options = {}); + for (var i = 0, l = this.models.length; i < l; i++) { + this._removeReference(this.models[i]); + } + options.previousModels = this.models; + this._reset(); + this.add(models, _.extend({silent: true}, options)); + if (!options.silent) this.trigger('reset', this, options); + return this; + }, + + // Add a model to the end of the collection. + push: function(model, options) { + model = this._prepareModel(model, options); + this.add(model, _.extend({at: this.length}, options)); + return model; + }, + + // Remove a model from the end of the collection. + pop: function(options) { + var model = this.at(this.length - 1); + this.remove(model, options); + return model; + }, + + // Add a model to the beginning of the collection. + unshift: function(model, options) { + model = this._prepareModel(model, options); + this.add(model, _.extend({at: 0}, options)); + return model; + }, + + // Remove a model from the beginning of the collection. + shift: function(options) { + var model = this.at(0); + this.remove(model, options); + return model; + }, + + // Slice out a sub-array of models from the collection. + slice: function(begin, end) { + return this.models.slice(begin, end); + }, + + // Get a model from the set by id. + get: function(obj) { + if (obj == null) return void 0; + return this._byId[obj.id != null ? obj.id : obj.cid || obj]; + }, + + // Get the model at the given index. + at: function(index) { + return this.models[index]; + }, + + // Return models with matching attributes. Useful for simple cases of + // `filter`. + where: function(attrs, first) { + if (_.isEmpty(attrs)) return first ? void 0 : []; + return this[first ? 'find' : 'filter'](function(model) { + for (var key in attrs) { + if (attrs[key] !== model.get(key)) return false; + } + return true; + }); + }, + + // Return the first model with matching attributes. Useful for simple cases + // of `find`. + findWhere: function(attrs) { + return this.where(attrs, true); + }, + + // Force the collection to re-sort itself. You don't need to call this under + // normal circumstances, as the set will maintain sort order as each item + // is added. + sort: function(options) { + if (!this.comparator) throw new Error('Cannot sort a set without a comparator'); + options || (options = {}); + + // Run sort based on type of `comparator`. + if (_.isString(this.comparator) || this.comparator.length === 1) { + this.models = this.sortBy(this.comparator, this); + } else { + this.models.sort(_.bind(this.comparator, this)); + } + + if (!options.silent) this.trigger('sort', this, options); + return this; + }, + + // Figure out the smallest index at which a model should be inserted so as + // to maintain order. + sortedIndex: function(model, value, context) { + value || (value = this.comparator); + var iterator = _.isFunction(value) ? value : function(model) { + return model.get(value); + }; + return _.sortedIndex(this.models, model, iterator, context); + }, + + // Pluck an attribute from each model in the collection. + pluck: function(attr) { + return _.invoke(this.models, 'get', attr); + }, + + // Fetch the default set of models for this collection, resetting the + // collection when they arrive. If `reset: true` is passed, the response + // data will be passed through the `reset` method instead of `set`. + fetch: function(options) { + options = options ? _.clone(options) : {}; + if (options.parse === void 0) options.parse = true; + var success = options.success; + var collection = this; + options.success = function(resp) { + var method = options.reset ? 'reset' : 'set'; + collection[method](resp, options); + if (success) success(collection, resp, options); + collection.trigger('sync', collection, resp, options); + }; + wrapError(this, options); + return this.sync('read', this, options); + }, + + // Create a new instance of a model in this collection. Add the model to the + // collection immediately, unless `wait: true` is passed, in which case we + // wait for the server to agree. + create: function(model, options) { + options = options ? _.clone(options) : {}; + if (!(model = this._prepareModel(model, options))) return false; + if (!options.wait) this.add(model, options); + var collection = this; + var success = options.success; + options.success = function(resp) { + if (options.wait) collection.add(model, options); + if (success) success(model, resp, options); + }; + model.save(null, options); + return model; + }, + + // **parse** converts a response into a list of models to be added to the + // collection. The default implementation is just to pass it through. + parse: function(resp, options) { + return resp; + }, + + // Create a new collection with an identical list of models as this one. + clone: function() { + return new this.constructor(this.models); + }, + + // Private method to reset all internal state. Called when the collection + // is first initialized or reset. + _reset: function() { + this.length = 0; + this.models = []; + this._byId = {}; + }, + + // Prepare a hash of attributes (or other model) to be added to this + // collection. + _prepareModel: function(attrs, options) { + if (attrs instanceof Model) { + if (!attrs.collection) attrs.collection = this; + return attrs; + } + options || (options = {}); + options.collection = this; + var model = new this.model(attrs, options); + if (!model._validate(attrs, options)) { + this.trigger('invalid', this, attrs, options); + return false; + } + return model; + }, + + // Internal method to sever a model's ties to a collection. + _removeReference: function(model) { + if (this === model.collection) delete model.collection; + model.off('all', this._onModelEvent, this); + }, + + // Internal method called every time a model in the set fires an event. + // Sets need to update their indexes when models change ids. All other + // events simply proxy through. "add" and "remove" events that originate + // in other collections are ignored. + _onModelEvent: function(event, model, collection, options) { + if ((event === 'add' || event === 'remove') && collection !== this) return; + if (event === 'destroy') this.remove(model, options); + if (model && event === 'change:' + model.idAttribute) { + delete this._byId[model.previous(model.idAttribute)]; + if (model.id != null) this._byId[model.id] = model; + } + this.trigger.apply(this, arguments); + } + + }); + + // Underscore methods that we want to implement on the Collection. + // 90% of the core usefulness of Backbone Collections is actually implemented + // right here: + var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl', + 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select', + 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke', + 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest', + 'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf', + 'isEmpty', 'chain']; + + // Mix in each Underscore method as a proxy to `Collection#models`. + _.each(methods, function(method) { + Collection.prototype[method] = function() { + var args = slice.call(arguments); + args.unshift(this.models); + return _[method].apply(_, args); + }; + }); + + // Underscore methods that take a property name as an argument. + var attributeMethods = ['groupBy', 'countBy', 'sortBy']; + + // Use attributes instead of properties. + _.each(attributeMethods, function(method) { + Collection.prototype[method] = function(value, context) { + var iterator = _.isFunction(value) ? value : function(model) { + return model.get(value); + }; + return _[method](this.models, iterator, context); + }; + }); + + // Backbone.View + // ------------- + + // Backbone Views are almost more convention than they are actual code. A View + // is simply a JavaScript object that represents a logical chunk of UI in the + // DOM. This might be a single item, an entire list, a sidebar or panel, or + // even the surrounding frame which wraps your whole app. Defining a chunk of + // UI as a **View** allows you to define your DOM events declaratively, without + // having to worry about render order ... and makes it easy for the view to + // react to specific changes in the state of your models. + + // Creating a Backbone.View creates its initial element outside of the DOM, + // if an existing element is not provided... + var View = Backbone.View = function(options) { + this.cid = _.uniqueId('view'); + this._configure(options || {}); + this._ensureElement(); + this.initialize.apply(this, arguments); + this.delegateEvents(); + }; + + // Cached regex to split keys for `delegate`. + var delegateEventSplitter = /^(\S+)\s*(.*)$/; + + // List of view options to be merged as properties. + var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events']; + + // Set up all inheritable **Backbone.View** properties and methods. + _.extend(View.prototype, Events, { + + // The default `tagName` of a View's element is `"div"`. + tagName: 'div', + + // jQuery delegate for element lookup, scoped to DOM elements within the + // current view. This should be prefered to global lookups where possible. + $: function(selector) { + return this.$el.find(selector); + }, + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // **render** is the core function that your view should override, in order + // to populate its element (`this.el`), with the appropriate HTML. The + // convention is for **render** to always return `this`. + render: function() { + return this; + }, + + // Remove this view by taking the element out of the DOM, and removing any + // applicable Backbone.Events listeners. + remove: function() { + this.$el.remove(); + this.stopListening(); + return this; + }, + + // Change the view's element (`this.el` property), including event + // re-delegation. + setElement: function(element, delegate) { + if (this.$el) this.undelegateEvents(); + this.$el = element instanceof Backbone.$ ? element : Backbone.$(element); + this.el = this.$el[0]; + if (delegate !== false) this.delegateEvents(); + return this; + }, + + // Set callbacks, where `this.events` is a hash of + // + // *{"event selector": "callback"}* + // + // { + // 'mousedown .title': 'edit', + // 'click .button': 'save' + // 'click .open': function(e) { ... } + // } + // + // pairs. Callbacks will be bound to the view, with `this` set properly. + // Uses event delegation for efficiency. + // Omitting the selector binds the event to `this.el`. + // This only works for delegate-able events: not `focus`, `blur`, and + // not `change`, `submit`, and `reset` in Internet Explorer. + delegateEvents: function(events) { + if (!(events || (events = _.result(this, 'events')))) return this; + this.undelegateEvents(); + for (var key in events) { + var method = events[key]; + if (!_.isFunction(method)) method = this[events[key]]; + if (!method) continue; + + var match = key.match(delegateEventSplitter); + var eventName = match[1], selector = match[2]; + method = _.bind(method, this); + eventName += '.delegateEvents' + this.cid; + if (selector === '') { + this.$el.on(eventName, method); + } else { + this.$el.on(eventName, selector, method); + } + } + return this; + }, + + // Clears all callbacks previously bound to the view with `delegateEvents`. + // You usually don't need to use this, but may wish to if you have multiple + // Backbone views attached to the same DOM element. + undelegateEvents: function() { + this.$el.off('.delegateEvents' + this.cid); + return this; + }, + + // Performs the initial configuration of a View with a set of options. + // Keys with special meaning *(e.g. model, collection, id, className)* are + // attached directly to the view. See `viewOptions` for an exhaustive + // list. + _configure: function(options) { + if (this.options) options = _.extend({}, _.result(this, 'options'), options); + _.extend(this, _.pick(options, viewOptions)); + this.options = options; + }, + + // Ensure that the View has a DOM element to render into. + // If `this.el` is a string, pass it through `$()`, take the first + // matching element, and re-assign it to `el`. Otherwise, create + // an element from the `id`, `className` and `tagName` properties. + _ensureElement: function() { + if (!this.el) { + var attrs = _.extend({}, _.result(this, 'attributes')); + if (this.id) attrs.id = _.result(this, 'id'); + if (this.className) attrs['class'] = _.result(this, 'className'); + var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs); + this.setElement($el, false); + } else { + this.setElement(_.result(this, 'el'), false); + } + } + + }); + + // Backbone.sync + // ------------- + + // Override this function to change the manner in which Backbone persists + // models to the server. You will be passed the type of request, and the + // model in question. By default, makes a RESTful Ajax request + // to the model's `url()`. Some possible customizations could be: + // + // * Use `setTimeout` to batch rapid-fire updates into a single request. + // * Send up the models as XML instead of JSON. + // * Persist models via WebSockets instead of Ajax. + // + // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests + // as `POST`, with a `_method` parameter containing the true HTTP method, + // as well as all requests with the body as `application/x-www-form-urlencoded` + // instead of `application/json` with the model in a param named `model`. + // Useful when interfacing with server-side languages like **PHP** that make + // it difficult to read the body of `PUT` requests. + Backbone.sync = function(method, model, options) { + var type = methodMap[method]; + + // Default options, unless specified. + _.defaults(options || (options = {}), { + emulateHTTP: Backbone.emulateHTTP, + emulateJSON: Backbone.emulateJSON + }); + + // Default JSON-request options. + var params = {type: type, dataType: 'json'}; + + // Ensure that we have a URL. + if (!options.url) { + params.url = _.result(model, 'url') || urlError(); + } + + // Ensure that we have the appropriate request data. + if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) { + params.contentType = 'application/json'; + params.data = JSON.stringify(options.attrs || model.toJSON(options)); + } + + // For older servers, emulate JSON by encoding the request into an HTML-form. + if (options.emulateJSON) { + params.contentType = 'application/x-www-form-urlencoded'; + params.data = params.data ? {model: params.data} : {}; + } + + // For older servers, emulate HTTP by mimicking the HTTP method with `_method` + // And an `X-HTTP-Method-Override` header. + if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) { + params.type = 'POST'; + if (options.emulateJSON) params.data._method = type; + var beforeSend = options.beforeSend; + options.beforeSend = function(xhr) { + xhr.setRequestHeader('X-HTTP-Method-Override', type); + if (beforeSend) return beforeSend.apply(this, arguments); + }; + } + + // Don't process data on a non-GET request. + if (params.type !== 'GET' && !options.emulateJSON) { + params.processData = false; + } + + // If we're sending a `PATCH` request, and we're in an old Internet Explorer + // that still has ActiveX enabled by default, override jQuery to use that + // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8. + if (params.type === 'PATCH' && window.ActiveXObject && + !(window.external && window.external.msActiveXFilteringEnabled)) { + params.xhr = function() { + return new ActiveXObject("Microsoft.XMLHTTP"); + }; + } + + // Make the request, allowing the user to override any Ajax options. + var xhr = options.xhr = Backbone.ajax(_.extend(params, options)); + model.trigger('request', model, xhr, options); + return xhr; + }; + + // Map from CRUD to HTTP for our default `Backbone.sync` implementation. + var methodMap = { + 'create': 'POST', + 'update': 'PUT', + 'patch': 'PATCH', + 'delete': 'DELETE', + 'read': 'GET' + }; + + // Set the default implementation of `Backbone.ajax` to proxy through to `$`. + // Override this if you'd like to use a different library. + Backbone.ajax = function() { + return Backbone.$.ajax.apply(Backbone.$, arguments); + }; + + // Backbone.Router + // --------------- + + // Routers map faux-URLs to actions, and fire events when routes are + // matched. Creating a new one sets its `routes` hash, if not set statically. + var Router = Backbone.Router = function(options) { + options || (options = {}); + if (options.routes) this.routes = options.routes; + this._bindRoutes(); + this.initialize.apply(this, arguments); + }; + + // Cached regular expressions for matching named param parts and splatted + // parts of route strings. + var optionalParam = /\((.*?)\)/g; + var namedParam = /(\(\?)?:\w+/g; + var splatParam = /\*\w+/g; + var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; + + // Set up all inheritable **Backbone.Router** properties and methods. + _.extend(Router.prototype, Events, { + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // Manually bind a single named route to a callback. For example: + // + // this.route('search/:query/p:num', 'search', function(query, num) { + // ... + // }); + // + route: function(route, name, callback) { + if (!_.isRegExp(route)) route = this._routeToRegExp(route); + if (_.isFunction(name)) { + callback = name; + name = ''; + } + if (!callback) callback = this[name]; + var router = this; + Backbone.history.route(route, function(fragment) { + var args = router._extractParameters(route, fragment); + callback && callback.apply(router, args); + router.trigger.apply(router, ['route:' + name].concat(args)); + router.trigger('route', name, args); + Backbone.history.trigger('route', router, name, args); + }); + return this; + }, + + // Simple proxy to `Backbone.history` to save a fragment into the history. + navigate: function(fragment, options) { + Backbone.history.navigate(fragment, options); + return this; + }, + + // Bind all defined routes to `Backbone.history`. We have to reverse the + // order of the routes here to support behavior where the most general + // routes can be defined at the bottom of the route map. + _bindRoutes: function() { + if (!this.routes) return; + this.routes = _.result(this, 'routes'); + var route, routes = _.keys(this.routes); + while ((route = routes.pop()) != null) { + this.route(route, this.routes[route]); + } + }, + + // Convert a route string into a regular expression, suitable for matching + // against the current location hash. + _routeToRegExp: function(route) { + route = route.replace(escapeRegExp, '\\$&') + .replace(optionalParam, '(?:$1)?') + .replace(namedParam, function(match, optional){ + return optional ? match : '([^\/]+)'; + }) + .replace(splatParam, '(.*?)'); + return new RegExp('^' + route + '$'); + }, + + // Given a route, and a URL fragment that it matches, return the array of + // extracted decoded parameters. Empty or unmatched parameters will be + // treated as `null` to normalize cross-browser behavior. + _extractParameters: function(route, fragment) { + var params = route.exec(fragment).slice(1); + return _.map(params, function(param) { + return param ? decodeURIComponent(param) : null; + }); + } + + }); + + // Backbone.History + // ---------------- + + // Handles cross-browser history management, based on either + // [pushState](http://diveintohtml5.info/history.html) and real URLs, or + // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange) + // and URL fragments. If the browser supports neither (old IE, natch), + // falls back to polling. + var History = Backbone.History = function() { + this.handlers = []; + _.bindAll(this, 'checkUrl'); + + // Ensure that `History` can be used outside of the browser. + if (typeof window !== 'undefined') { + this.location = window.location; + this.history = window.history; + } + }; + + // Cached regex for stripping a leading hash/slash and trailing space. + var routeStripper = /^[#\/]|\s+$/g; + + // Cached regex for stripping leading and trailing slashes. + var rootStripper = /^\/+|\/+$/g; + + // Cached regex for detecting MSIE. + var isExplorer = /msie [\w.]+/; + + // Cached regex for removing a trailing slash. + var trailingSlash = /\/$/; + + // Has the history handling already been started? + History.started = false; + + // Set up all inheritable **Backbone.History** properties and methods. + _.extend(History.prototype, Events, { + + // The default interval to poll for hash changes, if necessary, is + // twenty times a second. + interval: 50, + + // Gets the true hash value. Cannot use location.hash directly due to bug + // in Firefox where location.hash will always be decoded. + getHash: function(window) { + var match = (window || this).location.href.match(/#(.*)$/); + return match ? match[1] : ''; + }, + + // Get the cross-browser normalized URL fragment, either from the URL, + // the hash, or the override. + getFragment: function(fragment, forcePushState) { + if (fragment == null) { + if (this._hasPushState || !this._wantsHashChange || forcePushState) { + fragment = this.location.pathname; + var root = this.root.replace(trailingSlash, ''); + if (!fragment.indexOf(root)) fragment = fragment.substr(root.length); + } else { + fragment = this.getHash(); + } + } + return fragment.replace(routeStripper, ''); + }, + + // Start the hash change handling, returning `true` if the current URL matches + // an existing route, and `false` otherwise. + start: function(options) { + if (History.started) throw new Error("Backbone.history has already been started"); + History.started = true; + + // Figure out the initial configuration. Do we need an iframe? + // Is pushState desired ... is it available? + this.options = _.extend({}, {root: '/'}, this.options, options); + this.root = this.options.root; + this._wantsHashChange = this.options.hashChange !== false; + this._wantsPushState = !!this.options.pushState; + this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState); + var fragment = this.getFragment(); + var docMode = document.documentMode; + var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7)); + + // Normalize root to always include a leading and trailing slash. + this.root = ('/' + this.root + '/').replace(rootStripper, '/'); + + if (oldIE && this._wantsHashChange) { + this.iframe = Backbone.$('