├── .DS_Store ├── .bowerrc ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── .travis.yml ├── Gruntfile.js ├── README.md ├── book ├── .htaccess ├── 404.html ├── bower_components │ ├── codecode │ │ ├── .bower.json │ │ ├── .editorconfig │ │ ├── bower.json │ │ ├── codecode.css │ │ ├── codecode.js │ │ └── readme.md │ └── jquery │ │ ├── .bower.json │ │ ├── .editorconfig │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── .gitmodules │ │ ├── .jshintrc │ │ ├── .mailmap │ │ ├── AUTHORS.txt │ │ ├── CONTRIBUTING.md │ │ ├── Gruntfile.js │ │ ├── MIT-LICENSE.txt │ │ ├── README.md │ │ ├── bower.json │ │ ├── build │ │ ├── release-notes.js │ │ └── release.js │ │ ├── component.json │ │ ├── composer.json │ │ ├── jquery-migrate.js │ │ ├── jquery-migrate.min.js │ │ ├── jquery.js │ │ ├── jquery.min.js │ │ ├── jquery.min.map │ │ ├── package.json │ │ ├── speed │ │ ├── benchmark.js │ │ ├── benchmarker.css │ │ ├── benchmarker.js │ │ ├── closest.html │ │ ├── css.html │ │ ├── event.html │ │ ├── filter.html │ │ ├── find.html │ │ ├── index.html │ │ ├── jquery-basis.js │ │ └── slice.vs.concat.html │ │ ├── src │ │ ├── .jshintrc │ │ ├── ajax.js │ │ ├── ajax │ │ │ ├── jsonp.js │ │ │ ├── script.js │ │ │ └── xhr.js │ │ ├── attributes.js │ │ ├── callbacks.js │ │ ├── core.js │ │ ├── css.js │ │ ├── data.js │ │ ├── deferred.js │ │ ├── deprecated.js │ │ ├── dimensions.js │ │ ├── effects.js │ │ ├── event-alias.js │ │ ├── event.js │ │ ├── exports.js │ │ ├── intro.js │ │ ├── manipulation.js │ │ ├── offset.js │ │ ├── outro.js │ │ ├── queue.js │ │ ├── serialize.js │ │ ├── sizzle-jquery.js │ │ ├── support.js │ │ ├── traversing.js │ │ └── wrap.js │ │ └── test │ │ ├── .jshintignore │ │ ├── .jshintrc │ │ ├── data │ │ ├── 1x1.jpg │ │ ├── ajax │ │ │ └── unreleasedXHR.html │ │ ├── atom+xml.php │ │ ├── badcall.js │ │ ├── badjson.js │ │ ├── cleanScript.html │ │ ├── core │ │ │ └── cc_on.html │ │ ├── dashboard.xml │ │ ├── dimensions │ │ │ ├── documentLarge.html │ │ │ └── documentSmall.html │ │ ├── echoData.php │ │ ├── echoQuery.php │ │ ├── errorWithJSON.php │ │ ├── errorWithText.php │ │ ├── etag.php │ │ ├── evalScript.php │ │ ├── event │ │ │ ├── focusElem.html │ │ │ ├── longLoadScript.php │ │ │ ├── promiseReady.html │ │ │ └── syncReady.html │ │ ├── headers.php │ │ ├── if_modified_since.php │ │ ├── iframe.html │ │ ├── jquery-1.9.1.ajax_xhr.min.js │ │ ├── json.php │ │ ├── json_obj.js │ │ ├── jsonp.php │ │ ├── manipulation │ │ │ └── iframe-denied.html │ │ ├── name.html │ │ ├── name.php │ │ ├── nocontent.php │ │ ├── offset │ │ │ ├── absolute.html │ │ │ ├── body.html │ │ │ ├── fixed.html │ │ │ ├── relative.html │ │ │ ├── scroll.html │ │ │ ├── static.html │ │ │ └── table.html │ │ ├── params_html.php │ │ ├── readywaitasset.js │ │ ├── readywaitloader.js │ │ ├── script.php │ │ ├── selector │ │ │ ├── html5_selector.html │ │ │ └── sizzle_cache.html │ │ ├── statusText.php │ │ ├── support │ │ │ ├── bodyBackground.html │ │ │ ├── boxSizing.html │ │ │ ├── csp.js │ │ │ ├── csp.php │ │ │ ├── shrinkWrapBlocks.html │ │ │ └── testElementCrash.html │ │ ├── test.html │ │ ├── test.js │ │ ├── test.php │ │ ├── test2.html │ │ ├── test3.html │ │ ├── testinit.js │ │ ├── testrunner.js │ │ ├── testsuite.css │ │ ├── text.php │ │ ├── ua.txt │ │ ├── with_fries.xml │ │ └── with_fries_over_jsonp.php │ │ ├── delegatetest.html │ │ ├── hovertest.html │ │ ├── index.html │ │ ├── jquery.js │ │ ├── localfile.html │ │ ├── networkerror.html │ │ ├── readywait.html │ │ ├── unit │ │ ├── ajax.js │ │ ├── attributes.js │ │ ├── callbacks.js │ │ ├── core.js │ │ ├── css.js │ │ ├── data.js │ │ ├── deferred.js │ │ ├── deprecated.js │ │ ├── dimensions.js │ │ ├── effects.js │ │ ├── event.js │ │ ├── exports.js │ │ ├── manipulation.js │ │ ├── offset.js │ │ ├── queue.js │ │ ├── selector.js │ │ ├── serialize.js │ │ ├── support.js │ │ ├── traversing.js │ │ └── wrap.js │ │ └── xhtml.php ├── favicon.ico ├── images │ ├── base.png │ └── ns1.png ├── img │ ├── base.png │ └── ns1.png ├── index.html ├── metadata.xml ├── robots.txt ├── scripts │ └── vendor │ │ ├── shBrushJScript.js │ │ └── shCore.js ├── snippets │ ├── 01-JavaScript-Design-Patterns │ │ ├── 0-design-pattern-categorization.es2015.js │ │ ├── 0-design-pattern-categorization.es5.js │ │ ├── 1-the-constructor-pattern.es2015.js │ │ ├── 1-the-constructor-pattern.es5.js │ │ ├── 10-the-factory-pattern.es2015.js │ │ ├── 10-the-factory-pattern.es5.js │ │ ├── 11-the-mixin-pattern.es2015-2.js │ │ ├── 11-the-mixin-pattern.es2015.js │ │ ├── 11-the-mixin-pattern.es5.js │ │ ├── 12-the-decoration-pattern.es2015.js │ │ ├── 12-the-decoration-pattern.es5.js │ │ ├── 13-flyweight-pattern.es2015.js │ │ ├── 13-flyweight-pattern.es5.js │ │ ├── 2-the-module-pattern.es2015-2.js │ │ ├── 2-the-module-pattern.es2015.js │ │ ├── 2-the-module-pattern.es5.js │ │ ├── 3-the-revealing-module-pattern.es2015.js │ │ ├── 3-the-revealing-module-pattern.es5.js │ │ ├── 4-the-singleton-pattern.es2015.js │ │ ├── 4-the-singleton-pattern.es5.js │ │ ├── 5-the-observer-pattern.es2015.js │ │ ├── 5-the-observer-pattern.es5.js │ │ ├── 6-the-mediator-pattern.es2015.js │ │ ├── 6-the-mediator-pattern.es5.js │ │ ├── 7-the-prototype-pattern.es2015.js │ │ ├── 7-the-prototype-pattern.es5.js │ │ ├── 8-the-command-pattern.es2015.js │ │ ├── 8-the-command-pattern.es5.js │ │ ├── 9-the-facade-pattern.es2015.js │ │ └── 9-the-facade-pattern.es5.js │ ├── 02-JavaScript-MV*-Patterns │ │ ├── 14-MVC.es2015.js │ │ ├── 14-MVC.es5.js │ │ ├── 15-MVP.es5-no-changes.js │ │ ├── 16-MVVM.es5-no-changes.js │ │ └── 17-MVVM-with-looser-data-bindings.es5-no-changes.js │ ├── 03-Modern-Modular-JavaScript-Design-Patterns │ │ ├── 18-AMD.es2015.js │ │ ├── 18-AMD.es5.js │ │ ├── 19-CommonJS.es2015.js │ │ ├── 19-CommonJS.es5.js │ │ ├── 20-AMD-&&-CommonJS.es2015.js │ │ ├── 20-AMD-&&-CommonJS.es5.js │ │ └── 21-ES-harmony.es5-no-changes.js │ ├── 04-Design-Patterns-In-jQuery │ │ ├── 22-the-composite-pattern.es5-no-changes.js │ │ ├── 23-the-adapter-pattern.es5-no-changes.js │ │ ├── 24-the-facade-pattern.es5-no-changes.js │ │ ├── 25-the-observer-pattern.es2015.js │ │ ├── 25-the-observer-pattern.es5.js │ │ ├── 26-the-iterator-pattern.es2015.js │ │ ├── 26-the-iterator-pattern.es5.js │ │ ├── 27-the-lazy-initialization-pattern.es2015.js │ │ ├── 27-the-lazy-initialization-pattern.es5.js │ │ ├── 28-the-proxy-pattern.es5-no-changes.js │ │ ├── 29-the-builder-pattern.es2015.js │ │ ├── 29-the-builder-pattern.es5.js │ │ ├── 30-jQuery-plugin-design-patterns.es2015.js │ │ └── 30-jQuery-plugin-design-patterns.es5.js │ └── 05-Namespacing-Patterns │ │ ├── 31-namespacing-fundamentals.es2015.js │ │ ├── 31-namespacing-fundamentals.es5.js │ │ ├── 32-advanced-namespacing-patterns.es2015.js │ │ └── 32-advanced-namespacing-patterns.es5.js └── styles │ ├── base.css │ ├── main.css │ ├── print.css │ ├── sausage.css │ ├── shCore.css │ ├── shThemeRDark.css │ └── style.css ├── bower.json ├── cover └── cover.jpg ├── diagrams ├── command.png ├── constructor.png ├── facade.png ├── factory.png ├── flyweight.png ├── mediator.png ├── mixins.png ├── module.png ├── mvc.png ├── mvp.png ├── mvvm.png ├── observer.png ├── positioning.md ├── prototype.png ├── publishsubscribe.png └── singleton.png ├── extras ├── designpatterns-printable-referencecards │ └── design-patterns-printable.pdf └── dzone-designpatterns-cheatsheet │ └── rc008-designpatterns_online.pdf ├── package-lock.json ├── package.json └── test ├── .bowerrc ├── bower.json ├── index.html └── spec └── test.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/.DS_Store -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "book/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 4 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .tmp 4 | .sass-cache 5 | app/bower_components 6 | test/bower_components 7 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 4, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "jquery": true 21 | } 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/) 2 | [![Build Status](https://travis-ci.org/addyosmani/essential-js-design-patterns.png)](https://travis-ci.org/addyosmani/essential-js-design-patterns) 3 | 4 | 5 | 6 | # Learning JavaScript Design Patterns 7 | 8 | 9 | 10 | This is the source code for Learning JavaScript Design Patterns. It is licensed under the Creative Commons Attribution-Non Commercial-Share Alike 3.0 license. I hope you enjoy it, I hope it helps you learn, and I hope you'll support O'Reilly and me by purchasing a print copy of the book at [O'Reilly.com](http://shop.oreilly.com/product/0636920025832.do). 11 | 12 | Design patterns are reusable solutions to commonly occurring problems in software development and are a very useful tool to have at your disposal. You can read the latest version [online](http://addyosmani.com/resources/essentialjsdesignpatterns/book/) for free at any time. 13 | 14 | #### Why is this book needed? 15 | 16 | I wanted to write this book as I felt that patterns were an area a lot of new and intermediate JavaScript developers may not have had a chance to explore just yet and I'm hopeful my book will encourage you to check them out as they can be quite powerful. 17 | 18 | ### Contributing and Errata 19 | 20 | I'm always welcome to feedback on how the book can be improved. 21 | 22 | #### Pull requests 23 | 24 | If you would like to help improve the project, please feel free to send over a pull request. Some useful notes: 25 | 26 | * All changes should be made against the master branch. 27 | * The source of the book is currently in `book/index.html`. 28 | * Atomic commits make it easier to review changes. If you can separate changes out in this form, it'll save us time when trying to land. 29 | * Please review the version of the book [online](http://addyosmani.com/resources/essentialjsdesignpatterns/book/) before requesting a change. It is updated more frequently than the physical version of the book but we do bring changes back in every few months. 30 | 31 | #### Building the project 32 | 33 | Install dependencies : `npm install` 34 | Build the project: `grunt` 35 | Preview: `grunt serve` 36 | 37 | #### Additional formats 38 | 39 | The project is currently authored in HTML, however we do plan on introducing builds for other formats (PDF, ePub) shortly. In the mean time, official releases for other formats can be obtained via O'Reilly. 40 | 41 | ### Translations 42 | 43 | If you would like to get involved with translating this project to another language, please open up a new issue. O'Reilly have a process for handling translations to ensure that they go through the same review process that the English version goes through. 44 | 45 | So far, we've successfully had the book translated to Japanese. You can find that version on the [O'Reilly Japan](http://www.oreilly.co.jp/books/9784873116181/) site. 46 | 47 | ### License 48 | 49 | This book is released under a Creative Commons Attribution-Noncommercial- No Derivative Works 3.0 United States License. 50 | 51 | What this means it that the project is free to read and use, but the license does not permit commercial use of the material (i.e you can freely print out the book for your own use, but you can't sell it). I'm trying to best to publish all of my books in a free + purchased (if you would like to support these projects) form so I would greatly appreciate it if you would respect these terms. 52 | 53 | Copyright Addy Osmani, 2017. 54 | -------------------------------------------------------------------------------- /book/bower_components/codecode/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codecode", 3 | "version": "0.1.2", 4 | "author": "Stephen Sawchuk", 5 | "description": "codecode allows your readers to dock your syntax-highlighted code blocks to the bottom of the page, allowing them to refer back without losing their place in your article.", 6 | "homepage": "http://stephenplusplus.github.io/codecode", 7 | "main": [ 8 | "codecode.js", 9 | "codecode.css" 10 | ], 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/stephenplusplus/codecode.git" 14 | }, 15 | "dependencies": { 16 | "jquery": ">= 1.8.0" 17 | }, 18 | "_release": "0.1.2", 19 | "_resolution": { 20 | "type": "version", 21 | "tag": "0.1.2", 22 | "commit": "4cd82899a3c3296ac940fc390cc7d1de91d445f6" 23 | }, 24 | "_source": "git://github.com/stephenplusplus/codecode.git", 25 | "_target": "~0.1.2", 26 | "_originalSource": "codecode" 27 | } -------------------------------------------------------------------------------- /book/bower_components/codecode/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /book/bower_components/codecode/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codecode", 3 | "version": "0.1.1", 4 | "author": "Stephen Sawchuk", 5 | "description": "codecode allows your readers to dock your syntax-highlighted code blocks to the bottom of the page, allowing them to refer back without losing their place in your article.", 6 | "homepage": "http://stephenplusplus.github.io/codecode", 7 | "main": [ 8 | "codecode.js", 9 | "codecode.css" 10 | ], 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/stephenplusplus/codecode.git" 14 | }, 15 | "dependencies": { 16 | "jquery": ">= 1.8.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /book/bower_components/codecode/codecode.css: -------------------------------------------------------------------------------- 1 | .acodecode { 2 | cursor: pointer; 3 | } 4 | 5 | .acodecodeactive { 6 | cursor: default; 7 | } 8 | 9 | .codecodecode { 10 | position: fixed; 11 | z-index: 100; 12 | left: 2%; 13 | bottom: -30px; 14 | width: 96%; 15 | height: 0; 16 | max-height: 270px; 17 | text-align: left; 18 | } 19 | 20 | .codecodecode > div { 21 | box-shadow: 0 0 3px #444; 22 | } 23 | 24 | .codecodecontrols { 25 | height: 30px; 26 | margin-top: -30px; 27 | background-color: #fff; 28 | background-color: rgba(255, 255, 255, .8); 29 | border-radius: 8px 8px 0 0; 30 | } 31 | 32 | .codecodecontrols a { 33 | float: left; 34 | line-height: 30px; 35 | margin-left: 6px; 36 | font-family: Arial; 37 | font-size: 12px; 38 | } 39 | 40 | .codecodecontrols .closeCodeCode { 41 | float: right; 42 | margin-right: 6px; 43 | } 44 | 45 | .codecode, 46 | .acodecode.codecode { 47 | border-radius: 0 !important; 48 | position: relative !important; 49 | width: 100% !important; 50 | margin: 0 !important; 51 | overflow: auto !important; 52 | cursor: default !important; 53 | } 54 | 55 | div.codecode [id^=highlighter] div.bar.show, 56 | div.codecode [id^=highlighter] div.toolbar { 57 | display: none !important; 58 | }; -------------------------------------------------------------------------------- /book/bower_components/codecode/codecode.js: -------------------------------------------------------------------------------- 1 | (function ($, win, doc) { 2 | 'use strict'; 3 | 4 | var el = {}; 5 | var codePosition; 6 | 7 | el.body = $(doc.body); 8 | 9 | el.codecodecode = $([ 10 | '
', 11 | '
', 12 | ' go back to the code.', 13 | ' close.', 14 | '
', 15 | '
', 16 | '
' 17 | ].join('\n')); 18 | 19 | el.goBackToTheCode = el.codecodecode.find('.goBackToTheCode'); 20 | el.closeCodeCode = el.codecodecode.find('.closeCodeCode'); 21 | el.codecode = el.codecodecode.find('.codecode'); 22 | 23 | el.body.append(el.codecodecode); 24 | 25 | el.goBackToTheCode.on('click', goBackToTheCode); 26 | el.closeCodeCode.on('click', closeCodeCode); 27 | 28 | function goBackToTheCode(e) { 29 | e.preventDefault(); 30 | 31 | closeCodeCode(); 32 | 33 | el.body.animate({ scrollTop: codePosition - 20 }, 2000); 34 | }; 35 | 36 | function closeCodeCode(e, callback) { 37 | if ($.type(e) === 'object') { 38 | e.preventDefault(); 39 | } 40 | 41 | el.body.off('keyup'); 42 | 43 | el.codecodecode.animate({ bottom: '-300px' }, 300, callback || $.noop); 44 | 45 | $('.acodecodeactive').removeClass('acodecodeactive'); 46 | }; 47 | 48 | function openCodeCode(codeblock) { 49 | el.codecodecode.animate({ bottom: 0 }, 500); 50 | 51 | el.body.on('keyup', function (e) { 52 | if (e.which === 27) { 53 | closeCodeCode(); 54 | } 55 | }); 56 | 57 | codeblock.addClass('acodecodeactive'); 58 | }; 59 | 60 | function bindCodeCodeClick(selector) { 61 | el.body.on('click', selector, function () { 62 | var codeblock = $(this); 63 | var clone; 64 | 65 | if (codeblock.hasClass('acodecodeactive') || 66 | codeblock.hasClass('codecode')) { 67 | return; 68 | } 69 | 70 | codePosition = $(this).position().top; 71 | 72 | clone = codeblock.clone().addClass('codecode'); 73 | 74 | closeCodeCode(null, function () { 75 | el.codecode 76 | .empty() 77 | .append(clone.css('margin', '0 !important')) 78 | .height('auto'); 79 | 80 | el.codecodecode.height( 81 | (el.codecode.height() >= 270) ? 270 : el.codecode.height() 82 | ); 83 | 84 | el.codecode.height('100%'); 85 | }); 86 | 87 | openCodeCode(codeblock); 88 | }); 89 | }; 90 | 91 | $.fn.codecode = function () { 92 | bindCodeCodeClick(this.selector); 93 | 94 | return this.addClass('acodecode'); 95 | }; 96 | 97 | if (typeof SyntaxHighlighter !== 'undefined') { 98 | SyntaxHighlighter.all = (function () { 99 | var callSyntaxHighlighter = SyntaxHighlighter.all; 100 | var syntaxActivated = false; 101 | var checkForSyntaxEls; 102 | var tried = 0; 103 | 104 | function hasSyntaxBeenHighlighted() { 105 | if ($('.syntaxhighlighter').length > 0) { 106 | $('.syntaxhighlighter').codecode(); 107 | syntaxActivated = true; 108 | } 109 | 110 | if (syntaxActivated || tried++ > 50) { 111 | win.clearInterval(checkForSyntaxEls); 112 | } 113 | }; 114 | 115 | return function () { 116 | callSyntaxHighlighter(); 117 | 118 | checkForSyntaxEls = win.setInterval(hasSyntaxBeenHighlighted, 50); 119 | } 120 | })(); 121 | } 122 | })(jQuery, window, document); 123 | -------------------------------------------------------------------------------- /book/bower_components/codecode/readme.md: -------------------------------------------------------------------------------- 1 | # codecode. 2 | ---- 3 | 4 | ### What is `codecode`? 5 | If you spend any time reading a programmer's blog, there's a good chance you're going to be reading some code samples. I often have the problem of either looking ahead to the code without reading the text, or I just want to refer back to the code as I'm digesting the author's point. Our monitors are only so tall; I just want to be able to see both at the same time, without losing my place in either. 6 | 7 | That's what `codecode` helps with. It's a jQuery plug-in which will split your page in two, allowing your readers to see your code as they read your article. 8 | 9 | ### Will it work with [SyntaxHighlighter](http://alexgorbatchev.com/SyntaxHighlighter/)? 10 | Omg, yes! Just include `codecode.js` on your page, and... that's it! 11 | 12 | ### I use my own syntax highlighter / How do I use `codecode`? 13 | `codecode` can be dropped onto your website, anywhere code blocks are used, such as: 14 | 15 | ```html 16 | 17 | 18 | 19 | 20 | This is a website! 21 | ... 22 | ``` 23 | 24 | All you need to do is: 25 | 26 | 1. Have jQuery available. 27 | 2. Download and include `codecode.js` or `codecode.min.js`. 28 | 3. Call `$('.codeblock').codecode();` 29 | 30 | You're done! 31 | 32 | ### A demo! 33 | I've set up a [demo page](http://stephenplusplus.github.com/codecode) to show how `codecode` can help. 34 | -------------------------------------------------------------------------------- /book/bower_components/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "version": "1.10.2", 4 | "description": "jQuery component", 5 | "keywords": [ 6 | "jquery", 7 | "component" 8 | ], 9 | "main": "jquery.js", 10 | "license": "MIT", 11 | "homepage": "https://github.com/jquery/jquery", 12 | "_release": "1.10.2", 13 | "_resolution": { 14 | "type": "version", 15 | "tag": "1.10.2", 16 | "commit": "16b079b164d62bd807c612806842a13bf9b04d17" 17 | }, 18 | "_source": "git://github.com/jquery/jquery.git", 19 | "_target": "~1.10.2", 20 | "_originalSource": "jquery" 21 | } -------------------------------------------------------------------------------- /book/bower_components/jquery/.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | root = true 5 | 6 | 7 | [*] 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | # Tabs in JS unless otherwise specified 14 | [**.js] 15 | indent_style = tab 16 | 17 | [Makefile] 18 | indent_style = tab 19 | 20 | 21 | [speed/**.html] 22 | indent_style = tab 23 | 24 | [speed/**.css] 25 | indent_style = tab 26 | 27 | [speed/benchmarker.js] 28 | indent_style = space 29 | indent_size = 2 30 | 31 | 32 | [test/**.xml] 33 | indent_style = tab 34 | 35 | [test/**.php] 36 | indent_style = tab 37 | 38 | [test/**.html] 39 | indent_style = tab 40 | 41 | [test/**.css] 42 | indent_style = space 43 | indent_size = 8 44 | -------------------------------------------------------------------------------- /book/bower_components/jquery/.gitattributes: -------------------------------------------------------------------------------- 1 | * eol=lf 2 | *.jar binary 3 | -------------------------------------------------------------------------------- /book/bower_components/jquery/.gitignore: -------------------------------------------------------------------------------- 1 | src/selector-sizzle.js 2 | src/selector.js 3 | dist 4 | .project 5 | .settings 6 | *~ 7 | *.diff 8 | *.patch 9 | /*.html 10 | .DS_Store 11 | dist/.destination.json 12 | dist/.sizecache.json 13 | build/.sizecache.json 14 | node_modules 15 | -------------------------------------------------------------------------------- /book/bower_components/jquery/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/sizzle"] 2 | path = src/sizzle 3 | url = git://github.com/jquery/sizzle.git 4 | [submodule "test/qunit"] 5 | path = test/qunit 6 | url = git://github.com/jquery/qunit.git 7 | -------------------------------------------------------------------------------- /book/bower_components/jquery/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "boss": true, 3 | "curly": true, 4 | "eqeqeq": true, 5 | "eqnull": true, 6 | "expr": true, 7 | "immed": true, 8 | "noarg": true, 9 | "onevar": true, 10 | "quotmark": "double", 11 | "smarttabs": true, 12 | "trailing": true, 13 | "undef": true, 14 | "unused": true, 15 | 16 | "node": true 17 | } -------------------------------------------------------------------------------- /book/bower_components/jquery/.mailmap: -------------------------------------------------------------------------------- 1 | Adam Coulombe 2 | Adam J. Sontag 3 | Alexander Farkas 4 | Alexander Farkas 5 | Alexis Abril 6 | Andrew E Monat 7 | Anton Matzneller 8 | Anton Matzneller 9 | Batiste Bieler 10 | Benjamin Truyman 11 | Brandon Aaron 12 | Carl Danley 13 | Carl Fürstenberg 14 | Carl Fürstenberg 15 | Charles McNulty 16 | Colin Snover 17 | Corey Frang 18 | Dan Heberden 19 | Daniel Chatfield 20 | Daniel Gálvez 21 | Danil Somsikov 22 | Dave Methvin 23 | Dave Reed 24 | David Fox 25 | Devin Cooper 26 | Dmitry Gusev 27 | Earle Castledine 28 | Erick Ruiz de Chávez 29 | Gianni Alessandro Chiappetta 30 | Heungsub Lee 31 | Iraê Carvalho 32 | Isaac Z. Schlueter 33 | Ismail Khair 34 | James Burke 35 | James Padolsey 36 | Jason Bedard 37 | Jay Merrifield 38 | Jay Merrifield 39 | Jean Boussier 40 | Jephte Clain 41 | Jess Thrysoee 42 | Joao Henrique de Andrade Bruni 43 | Joe Presbrey 44 | John Resig 45 | John Resig 46 | Jordan Boesch 47 | Josh Varner 48 | Julian Aubourg 49 | Julian Aubourg 50 | Julian Aubourg 51 | Jörn Zaefferer 52 | Jörn Zaefferer 53 | Jörn Zaefferer 54 | Karl Swedberg 55 | Kris Borchers 56 | Lee Carpenter 57 | Li Xudong 58 | Louis-Rémi Babé 59 | Louis-Rémi Babé 60 | Louis-Rémi Babé 61 | Louis-Rémi Babé 62 | Marcel Greter 63 | Matthias Jäggli 64 | Michael Murray 65 | Michał Gołębiowski 66 | Michał Gołębiowski 67 | Mike Alsup 68 | Nguyen Phuc Lam 69 | Oleg Gaidarenko 70 | Rafaël Blais Masson 71 | Richard D. Worth 72 | Rick Waldron 73 | Rick Waldron 74 | Robert Katić 75 | Ron Otten 76 | Sai Lung Wong 77 | Scott González 78 | Scott Jehl 79 | Sebastian Burkhard 80 | Timmy Willison 81 | Timmy Willison 82 | Timo Tijhof 83 | TJ Holowaychuk 84 | Tom H Fuertes 85 | Tom H Fuertes Tom H Fuertes 86 | Tom Viner 87 | Xavi Ramirez 88 | Xavier Montillet 89 | Yehuda Katz 90 | Yehuda Katz 91 | Yehuda Katz 92 | Yehuda Katz 93 | Yiming He 94 | Terry Jones 95 | -------------------------------------------------------------------------------- /book/bower_components/jquery/MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2013 jQuery Foundation and other contributors 2 | http://jquery.com/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /book/bower_components/jquery/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "version": "1.10.2", 4 | "description": "jQuery component", 5 | "keywords": [ 6 | "jquery", 7 | "component" 8 | ], 9 | "main": "jquery.js", 10 | "license": "MIT" 11 | } 12 | -------------------------------------------------------------------------------- /book/bower_components/jquery/build/release-notes.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* 3 | * jQuery Release Note Generator 4 | */ 5 | 6 | var fs = require("fs"), 7 | http = require("http"), 8 | extract = /(.*?)<[^"]+"component">\s*(\S+)/g, 9 | categories = [], 10 | version = process.argv[2]; 11 | 12 | if ( !/^\d+\.\d+/.test( version ) ) { 13 | console.error( "Invalid version number: " + version ); 14 | process.exit( 1 ); 15 | } 16 | 17 | http.request({ 18 | host: "bugs.jquery.com", 19 | port: 80, 20 | method: "GET", 21 | path: "/query?status=closed&resolution=fixed&max=400&component=!web&order=component&milestone=" + version 22 | }, function (res) { 23 | var data = []; 24 | 25 | res.on( "data", function( chunk ) { 26 | data.push( chunk ); 27 | }); 28 | 29 | res.on( "end", function() { 30 | var match, 31 | file = data.join(""), 32 | cur; 33 | 34 | while ( (match = extract.exec( file )) ) { 35 | if ( "#" + match[1] !== match[2] ) { 36 | var cat = match[3]; 37 | 38 | if ( !cur || cur !== cat ) { 39 | if ( cur ) { 40 | console.log(""); 41 | } 42 | cur = cat; 43 | console.log( "

" + cat.charAt(0).toUpperCase() + cat.slice(1) + "

" ); 44 | console.log("
"); 55 | } 56 | 57 | }); 58 | }).end(); 59 | 60 | -------------------------------------------------------------------------------- /book/bower_components/jquery/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "repo": "components/jquery", 4 | "version": "1.10.2", 5 | "description": "jQuery component", 6 | "keywords": [ 7 | "jquery", 8 | "component" 9 | ], 10 | "main": "jquery.js", 11 | "scripts": [ 12 | "jquery.js" 13 | ], 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /book/bower_components/jquery/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "components/jquery", 3 | "description": "jQuery JavaScript Library", 4 | "type": "component", 5 | "homepage": "http://jquery.com", 6 | "license": "MIT", 7 | "support": { 8 | "irc": "irc://irc.freenode.org/jquery", 9 | "issues": "http://bugs.jquery.com", 10 | "forum": "http://forum.jquery.com", 11 | "wiki": "http://docs.jquery.com/", 12 | "source": "https://github.com/jquery/jquery" 13 | }, 14 | "authors": [ 15 | { 16 | "name": "John Resig", 17 | "email": "jeresig@gmail.com" 18 | } 19 | ], 20 | "require": { 21 | "robloach/component-installer": "*" 22 | }, 23 | "extra": { 24 | "component": { 25 | "scripts": [ 26 | "jquery.js" 27 | ], 28 | "files": [ 29 | "jquery.min.js", 30 | "jquery-migrate.js", 31 | "jquery-migrate.min.js" 32 | ] 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /book/bower_components/jquery/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "title": "jQuery", 4 | "description": "JavaScript library for DOM operations", 5 | "version": "1.10.2", 6 | "homepage": "http://jquery.com", 7 | "author": { 8 | "name": "jQuery Foundation and other contributors", 9 | "url": "https://github.com/jquery/jquery/blob/master/AUTHORS.txt" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/jquery/jquery.git" 14 | }, 15 | "bugs": { 16 | "url": "http://bugs.jquery.com" 17 | }, 18 | "licenses": [ 19 | { 20 | "type": "MIT", 21 | "url": "https://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt" 22 | } 23 | ], 24 | "dependencies": {}, 25 | "devDependencies": { 26 | "grunt-compare-size": "~0.4.0", 27 | "grunt-git-authors": "1.2.0", 28 | "grunt-update-submodules": "0.2.0", 29 | "grunt-contrib-watch": "0.3.1", 30 | "grunt-contrib-jshint": "0.3.0", 31 | "grunt-contrib-uglify": "0.2.0", 32 | "grunt": "0.4.1", 33 | "gzip-js": "0.3.1", 34 | "testswarm": "~1.1.0", 35 | "archiver": "~0.4.2" 36 | }, 37 | "keywords": [] 38 | } 39 | -------------------------------------------------------------------------------- /book/bower_components/jquery/speed/benchmark.js: -------------------------------------------------------------------------------- 1 | // Runs a function many times without the function call overhead 2 | function benchmark(fn, times, name){ 3 | fn = fn.toString(); 4 | var s = fn.indexOf('{')+1, 5 | e = fn.lastIndexOf('}'); 6 | fn = fn.substring(s,e); 7 | 8 | return benchmarkString(fn, times, name); 9 | } 10 | 11 | function benchmarkString(fn, times, name) { 12 | var fn = new Function("i", "var t=new Date; while(i--) {" + fn + "}; return new Date - t")(times) 13 | fn.displayName = name || "benchmarked"; 14 | return fn; 15 | } 16 | -------------------------------------------------------------------------------- /book/bower_components/jquery/speed/benchmarker.css: -------------------------------------------------------------------------------- 1 | 2 | .dialog { 3 | margin-bottom: 1em; 4 | } 5 | a.expand { 6 | background: #e3e3e3; 7 | } 8 | 9 | div#time-test { 10 | font-family: Arial, Helvetica, sans-serif; 11 | font-size: 62.5%; 12 | } 13 | 14 | td.test button { 15 | float: right; 16 | } 17 | 18 | table { 19 | border: 1px solid #000; 20 | } 21 | 22 | table td, table th { 23 | border: 1px solid #000; 24 | padding: 10px; 25 | } 26 | 27 | td.winner { 28 | background-color: #cfc; 29 | } 30 | 31 | td.tie { 32 | background-color: #ffc; 33 | } 34 | 35 | td.fail { 36 | background-color: #f99; 37 | font-weight: bold; 38 | text-align: center; 39 | } 40 | 41 | tfoot td { 42 | text-align: center; 43 | } 44 | 45 | #time-test { 46 | margin: 1em 0; 47 | padding: .5em; 48 | background: #e3e3e3; 49 | } 50 | #time-taken { 51 | font-weight: bold; 52 | } 53 | 54 | span.wins { 55 | color: #330; 56 | } 57 | 58 | span.fails { 59 | color: #900; 60 | } 61 | 62 | div.buttons { 63 | margin-top: 10px; 64 | margin-bottom: 10px; 65 | } 66 | -------------------------------------------------------------------------------- /book/bower_components/jquery/speed/closest.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test .closest() Performance 5 | 6 | 7 | 8 | 9 | 25 | 26 | 27 |
28 |

Hello

29 |
30 |
31 |

lorem ipsum

32 |

dolor sit amet

33 |
34 |
35 |
36 |
    37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /book/bower_components/jquery/speed/css.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test Event Handling Performance 5 | 6 | 7 | 8 | 9 | 76 | 77 | 78 | 79 |

    Getting Values: Loading...

    80 |

    Setting Values: Loading...

    81 | 82 | 83 | -------------------------------------------------------------------------------- /book/bower_components/jquery/speed/event.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test Event Handling Performance 5 | 6 | 7 | 8 | 9 | 53 | 54 | 55 |

    Move the mouse, please!

    56 |

    57 | 58 | 59 | -------------------------------------------------------------------------------- /book/bower_components/jquery/speed/slice.vs.concat.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/bower_components/jquery/src/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "boss": true, 3 | "curly": true, 4 | "eqeqeq": true, 5 | "eqnull": true, 6 | "expr": true, 7 | "immed": true, 8 | "noarg": true, 9 | "onevar": true, 10 | "quotmark": "double", 11 | "smarttabs": true, 12 | "trailing": true, 13 | "undef": true, 14 | "unused": true, 15 | 16 | "evil": true, 17 | "sub": true, 18 | 19 | "browser": true, 20 | "wsh": true, 21 | 22 | "globals": { 23 | "define": true, 24 | "module": true, 25 | "jQuery": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /book/bower_components/jquery/src/ajax/jsonp.js: -------------------------------------------------------------------------------- 1 | var oldCallbacks = [], 2 | rjsonp = /(=)\?(?=&|$)|\?\?/; 3 | 4 | // Default jsonp settings 5 | jQuery.ajaxSetup({ 6 | jsonp: "callback", 7 | jsonpCallback: function() { 8 | var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) ); 9 | this[ callback ] = true; 10 | return callback; 11 | } 12 | }); 13 | 14 | // Detect, normalize options and install callbacks for jsonp requests 15 | jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { 16 | 17 | var callbackName, overwritten, responseContainer, 18 | jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? 19 | "url" : 20 | typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data" 21 | ); 22 | 23 | // Handle iff the expected data type is "jsonp" or we have a parameter to set 24 | if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { 25 | 26 | // Get callback name, remembering preexisting value associated with it 27 | callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? 28 | s.jsonpCallback() : 29 | s.jsonpCallback; 30 | 31 | // Insert callback into url or form data 32 | if ( jsonProp ) { 33 | s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); 34 | } else if ( s.jsonp !== false ) { 35 | s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; 36 | } 37 | 38 | // Use data converter to retrieve json after script execution 39 | s.converters["script json"] = function() { 40 | if ( !responseContainer ) { 41 | jQuery.error( callbackName + " was not called" ); 42 | } 43 | return responseContainer[ 0 ]; 44 | }; 45 | 46 | // force json dataType 47 | s.dataTypes[ 0 ] = "json"; 48 | 49 | // Install callback 50 | overwritten = window[ callbackName ]; 51 | window[ callbackName ] = function() { 52 | responseContainer = arguments; 53 | }; 54 | 55 | // Clean-up function (fires after converters) 56 | jqXHR.always(function() { 57 | // Restore preexisting value 58 | window[ callbackName ] = overwritten; 59 | 60 | // Save back as free 61 | if ( s[ callbackName ] ) { 62 | // make sure that re-using the options doesn't screw things around 63 | s.jsonpCallback = originalSettings.jsonpCallback; 64 | 65 | // save the callback name for future use 66 | oldCallbacks.push( callbackName ); 67 | } 68 | 69 | // Call if it was a function and we have a response 70 | if ( responseContainer && jQuery.isFunction( overwritten ) ) { 71 | overwritten( responseContainer[ 0 ] ); 72 | } 73 | 74 | responseContainer = overwritten = undefined; 75 | }); 76 | 77 | // Delegate to script 78 | return "script"; 79 | } 80 | }); 81 | -------------------------------------------------------------------------------- /book/bower_components/jquery/src/ajax/script.js: -------------------------------------------------------------------------------- 1 | // Install script dataType 2 | jQuery.ajaxSetup({ 3 | accepts: { 4 | script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" 5 | }, 6 | contents: { 7 | script: /(?:java|ecma)script/ 8 | }, 9 | converters: { 10 | "text script": function( text ) { 11 | jQuery.globalEval( text ); 12 | return text; 13 | } 14 | } 15 | }); 16 | 17 | // Handle cache's special case and global 18 | jQuery.ajaxPrefilter( "script", function( s ) { 19 | if ( s.cache === undefined ) { 20 | s.cache = false; 21 | } 22 | if ( s.crossDomain ) { 23 | s.type = "GET"; 24 | s.global = false; 25 | } 26 | }); 27 | 28 | // Bind script tag hack transport 29 | jQuery.ajaxTransport( "script", function(s) { 30 | 31 | // This transport only deals with cross domain requests 32 | if ( s.crossDomain ) { 33 | 34 | var script, 35 | head = document.head || jQuery("head")[0] || document.documentElement; 36 | 37 | return { 38 | 39 | send: function( _, callback ) { 40 | 41 | script = document.createElement("script"); 42 | 43 | script.async = true; 44 | 45 | if ( s.scriptCharset ) { 46 | script.charset = s.scriptCharset; 47 | } 48 | 49 | script.src = s.url; 50 | 51 | // Attach handlers for all browsers 52 | script.onload = script.onreadystatechange = function( _, isAbort ) { 53 | 54 | if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { 55 | 56 | // Handle memory leak in IE 57 | script.onload = script.onreadystatechange = null; 58 | 59 | // Remove the script 60 | if ( script.parentNode ) { 61 | script.parentNode.removeChild( script ); 62 | } 63 | 64 | // Dereference the script 65 | script = null; 66 | 67 | // Callback if not abort 68 | if ( !isAbort ) { 69 | callback( 200, "success" ); 70 | } 71 | } 72 | }; 73 | 74 | // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending 75 | // Use native DOM manipulation to avoid our domManip AJAX trickery 76 | head.insertBefore( script, head.firstChild ); 77 | }, 78 | 79 | abort: function() { 80 | if ( script ) { 81 | script.onload( undefined, true ); 82 | } 83 | } 84 | }; 85 | } 86 | }); 87 | -------------------------------------------------------------------------------- /book/bower_components/jquery/src/deprecated.js: -------------------------------------------------------------------------------- 1 | // Limit scope pollution from any deprecated API 2 | // (function() { 3 | 4 | // The number of elements contained in the matched element set 5 | jQuery.fn.size = function() { 6 | return this.length; 7 | }; 8 | 9 | jQuery.fn.andSelf = jQuery.fn.addBack; 10 | 11 | // })(); 12 | -------------------------------------------------------------------------------- /book/bower_components/jquery/src/dimensions.js: -------------------------------------------------------------------------------- 1 | // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods 2 | jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { 3 | jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { 4 | // margin is only for outerHeight, outerWidth 5 | jQuery.fn[ funcName ] = function( margin, value ) { 6 | var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), 7 | extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); 8 | 9 | return jQuery.access( this, function( elem, type, value ) { 10 | var doc; 11 | 12 | if ( jQuery.isWindow( elem ) ) { 13 | // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there 14 | // isn't a whole lot we can do. See pull request at this URL for discussion: 15 | // https://github.com/jquery/jquery/pull/764 16 | return elem.document.documentElement[ "client" + name ]; 17 | } 18 | 19 | // Get document width or height 20 | if ( elem.nodeType === 9 ) { 21 | doc = elem.documentElement; 22 | 23 | // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest 24 | // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. 25 | return Math.max( 26 | elem.body[ "scroll" + name ], doc[ "scroll" + name ], 27 | elem.body[ "offset" + name ], doc[ "offset" + name ], 28 | doc[ "client" + name ] 29 | ); 30 | } 31 | 32 | return value === undefined ? 33 | // Get width or height on the element, requesting but not forcing parseFloat 34 | jQuery.css( elem, type, extra ) : 35 | 36 | // Set width or height on the element 37 | jQuery.style( elem, type, value, extra ); 38 | }, type, chainable ? margin : undefined, chainable, null ); 39 | }; 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /book/bower_components/jquery/src/event-alias.js: -------------------------------------------------------------------------------- 1 | jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + 2 | "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + 3 | "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { 4 | 5 | // Handle event binding 6 | jQuery.fn[ name ] = function( data, fn ) { 7 | return arguments.length > 0 ? 8 | this.on( name, null, data, fn ) : 9 | this.trigger( name ); 10 | }; 11 | }); 12 | 13 | jQuery.fn.extend({ 14 | hover: function( fnOver, fnOut ) { 15 | return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); 16 | }, 17 | 18 | bind: function( types, data, fn ) { 19 | return this.on( types, null, data, fn ); 20 | }, 21 | unbind: function( types, fn ) { 22 | return this.off( types, null, fn ); 23 | }, 24 | 25 | delegate: function( selector, types, data, fn ) { 26 | return this.on( types, selector, data, fn ); 27 | }, 28 | undelegate: function( selector, types, fn ) { 29 | // ( namespace ) or ( selector, types [, fn] ) 30 | return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /book/bower_components/jquery/src/exports.js: -------------------------------------------------------------------------------- 1 | if ( typeof module === "object" && module && typeof module.exports === "object" ) { 2 | // Expose jQuery as module.exports in loaders that implement the Node 3 | // module pattern (including browserify). Do not create the global, since 4 | // the user will be storing it themselves locally, and globals are frowned 5 | // upon in the Node module world. 6 | module.exports = jQuery; 7 | } else { 8 | // Otherwise expose jQuery to the global object as usual 9 | window.jQuery = window.$ = jQuery; 10 | 11 | // Register as a named AMD module, since jQuery can be concatenated with other 12 | // files that may use define, but not via a proper concatenation script that 13 | // understands anonymous AMD modules. A named AMD is safest and most robust 14 | // way to register. Lowercase jquery is used because AMD module names are 15 | // derived from file names, and jQuery is normally delivered in a lowercase 16 | // file name. Do this after creating the global so that if an AMD module wants 17 | // to call noConflict to hide this version of jQuery, it will work. 18 | if ( typeof define === "function" && define.amd ) { 19 | define( "jquery", [], function () { return jQuery; } ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /book/bower_components/jquery/src/intro.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery JavaScript Library v@VERSION 3 | * http://jquery.com/ 4 | * 5 | * Includes Sizzle.js 6 | * http://sizzlejs.com/ 7 | * 8 | * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors 9 | * Released under the MIT license 10 | * http://jquery.org/license 11 | * 12 | * Date: @DATE 13 | */ 14 | (function( window, undefined ) { 15 | 16 | // Can't do this because several apps including ASP.NET trace 17 | // the stack via arguments.caller.callee and Firefox dies if 18 | // you try to trace through "use strict" call chains. (#13335) 19 | // Support: Firefox 18+ 20 | //"use strict"; 21 | -------------------------------------------------------------------------------- /book/bower_components/jquery/src/outro.js: -------------------------------------------------------------------------------- 1 | 2 | })( window ); 3 | -------------------------------------------------------------------------------- /book/bower_components/jquery/src/queue.js: -------------------------------------------------------------------------------- 1 | jQuery.extend({ 2 | queue: function( elem, type, data ) { 3 | var queue; 4 | 5 | if ( elem ) { 6 | type = ( type || "fx" ) + "queue"; 7 | queue = jQuery._data( elem, type ); 8 | 9 | // Speed up dequeue by getting out quickly if this is just a lookup 10 | if ( data ) { 11 | if ( !queue || jQuery.isArray(data) ) { 12 | queue = jQuery._data( elem, type, jQuery.makeArray(data) ); 13 | } else { 14 | queue.push( data ); 15 | } 16 | } 17 | return queue || []; 18 | } 19 | }, 20 | 21 | dequeue: function( elem, type ) { 22 | type = type || "fx"; 23 | 24 | var queue = jQuery.queue( elem, type ), 25 | startLength = queue.length, 26 | fn = queue.shift(), 27 | hooks = jQuery._queueHooks( elem, type ), 28 | next = function() { 29 | jQuery.dequeue( elem, type ); 30 | }; 31 | 32 | // If the fx queue is dequeued, always remove the progress sentinel 33 | if ( fn === "inprogress" ) { 34 | fn = queue.shift(); 35 | startLength--; 36 | } 37 | 38 | if ( fn ) { 39 | 40 | // Add a progress sentinel to prevent the fx queue from being 41 | // automatically dequeued 42 | if ( type === "fx" ) { 43 | queue.unshift( "inprogress" ); 44 | } 45 | 46 | // clear up the last queue stop function 47 | delete hooks.stop; 48 | fn.call( elem, next, hooks ); 49 | } 50 | 51 | if ( !startLength && hooks ) { 52 | hooks.empty.fire(); 53 | } 54 | }, 55 | 56 | // not intended for public consumption - generates a queueHooks object, or returns the current one 57 | _queueHooks: function( elem, type ) { 58 | var key = type + "queueHooks"; 59 | return jQuery._data( elem, key ) || jQuery._data( elem, key, { 60 | empty: jQuery.Callbacks("once memory").add(function() { 61 | jQuery._removeData( elem, type + "queue" ); 62 | jQuery._removeData( elem, key ); 63 | }) 64 | }); 65 | } 66 | }); 67 | 68 | jQuery.fn.extend({ 69 | queue: function( type, data ) { 70 | var setter = 2; 71 | 72 | if ( typeof type !== "string" ) { 73 | data = type; 74 | type = "fx"; 75 | setter--; 76 | } 77 | 78 | if ( arguments.length < setter ) { 79 | return jQuery.queue( this[0], type ); 80 | } 81 | 82 | return data === undefined ? 83 | this : 84 | this.each(function() { 85 | var queue = jQuery.queue( this, type, data ); 86 | 87 | // ensure a hooks for this queue 88 | jQuery._queueHooks( this, type ); 89 | 90 | if ( type === "fx" && queue[0] !== "inprogress" ) { 91 | jQuery.dequeue( this, type ); 92 | } 93 | }); 94 | }, 95 | dequeue: function( type ) { 96 | return this.each(function() { 97 | jQuery.dequeue( this, type ); 98 | }); 99 | }, 100 | // Based off of the plugin by Clint Helfers, with permission. 101 | // http://blindsignals.com/index.php/2009/07/jquery-delay/ 102 | delay: function( time, type ) { 103 | time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; 104 | type = type || "fx"; 105 | 106 | return this.queue( type, function( next, hooks ) { 107 | var timeout = setTimeout( next, time ); 108 | hooks.stop = function() { 109 | clearTimeout( timeout ); 110 | }; 111 | }); 112 | }, 113 | clearQueue: function( type ) { 114 | return this.queue( type || "fx", [] ); 115 | }, 116 | // Get a promise resolved when queues of a certain type 117 | // are emptied (fx is the type by default) 118 | promise: function( type, obj ) { 119 | var tmp, 120 | count = 1, 121 | defer = jQuery.Deferred(), 122 | elements = this, 123 | i = this.length, 124 | resolve = function() { 125 | if ( !( --count ) ) { 126 | defer.resolveWith( elements, [ elements ] ); 127 | } 128 | }; 129 | 130 | if ( typeof type !== "string" ) { 131 | obj = type; 132 | type = undefined; 133 | } 134 | type = type || "fx"; 135 | 136 | while( i-- ) { 137 | tmp = jQuery._data( elements[ i ], type + "queueHooks" ); 138 | if ( tmp && tmp.empty ) { 139 | count++; 140 | tmp.empty.add( resolve ); 141 | } 142 | } 143 | resolve(); 144 | return defer.promise( obj ); 145 | } 146 | }); 147 | -------------------------------------------------------------------------------- /book/bower_components/jquery/src/serialize.js: -------------------------------------------------------------------------------- 1 | var r20 = /%20/g, 2 | rbracket = /\[\]$/, 3 | rCRLF = /\r?\n/g, 4 | rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, 5 | rsubmittable = /^(?:input|select|textarea|keygen)/i; 6 | 7 | jQuery.fn.extend({ 8 | serialize: function() { 9 | return jQuery.param( this.serializeArray() ); 10 | }, 11 | serializeArray: function() { 12 | return this.map(function(){ 13 | // Can add propHook for "elements" to filter or add form elements 14 | var elements = jQuery.prop( this, "elements" ); 15 | return elements ? jQuery.makeArray( elements ) : this; 16 | }) 17 | .filter(function(){ 18 | var type = this.type; 19 | // Use .is(":disabled") so that fieldset[disabled] works 20 | return this.name && !jQuery( this ).is( ":disabled" ) && 21 | rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && 22 | ( this.checked || !manipulation_rcheckableType.test( type ) ); 23 | }) 24 | .map(function( i, elem ){ 25 | var val = jQuery( this ).val(); 26 | 27 | return val == null ? 28 | null : 29 | jQuery.isArray( val ) ? 30 | jQuery.map( val, function( val ){ 31 | return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 32 | }) : 33 | { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 34 | }).get(); 35 | } 36 | }); 37 | 38 | //Serialize an array of form elements or a set of 39 | //key/values into a query string 40 | jQuery.param = function( a, traditional ) { 41 | var prefix, 42 | s = [], 43 | add = function( key, value ) { 44 | // If value is a function, invoke it and return its value 45 | value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); 46 | s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); 47 | }; 48 | 49 | // Set traditional to true for jQuery <= 1.3.2 behavior. 50 | if ( traditional === undefined ) { 51 | traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; 52 | } 53 | 54 | // If an array was passed in, assume that it is an array of form elements. 55 | if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { 56 | // Serialize the form elements 57 | jQuery.each( a, function() { 58 | add( this.name, this.value ); 59 | }); 60 | 61 | } else { 62 | // If traditional, encode the "old" way (the way 1.3.2 or older 63 | // did it), otherwise encode params recursively. 64 | for ( prefix in a ) { 65 | buildParams( prefix, a[ prefix ], traditional, add ); 66 | } 67 | } 68 | 69 | // Return the resulting serialization 70 | return s.join( "&" ).replace( r20, "+" ); 71 | }; 72 | 73 | function buildParams( prefix, obj, traditional, add ) { 74 | var name; 75 | 76 | if ( jQuery.isArray( obj ) ) { 77 | // Serialize array item. 78 | jQuery.each( obj, function( i, v ) { 79 | if ( traditional || rbracket.test( prefix ) ) { 80 | // Treat each array item as a scalar. 81 | add( prefix, v ); 82 | 83 | } else { 84 | // Item is non-scalar (array or object), encode its numeric index. 85 | buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); 86 | } 87 | }); 88 | 89 | } else if ( !traditional && jQuery.type( obj ) === "object" ) { 90 | // Serialize object item. 91 | for ( name in obj ) { 92 | buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); 93 | } 94 | 95 | } else { 96 | // Serialize scalar item. 97 | add( prefix, obj ); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /book/bower_components/jquery/src/sizzle-jquery.js: -------------------------------------------------------------------------------- 1 | jQuery.find = Sizzle; 2 | jQuery.expr = Sizzle.selectors; 3 | jQuery.expr[":"] = jQuery.expr.pseudos; 4 | jQuery.unique = Sizzle.uniqueSort; 5 | jQuery.text = Sizzle.getText; 6 | jQuery.isXMLDoc = Sizzle.isXML; 7 | jQuery.contains = Sizzle.contains; 8 | -------------------------------------------------------------------------------- /book/bower_components/jquery/src/wrap.js: -------------------------------------------------------------------------------- 1 | jQuery.fn.extend({ 2 | wrapAll: function( html ) { 3 | if ( jQuery.isFunction( html ) ) { 4 | return this.each(function(i) { 5 | jQuery(this).wrapAll( html.call(this, i) ); 6 | }); 7 | } 8 | 9 | if ( this[0] ) { 10 | // The elements to wrap the target around 11 | var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); 12 | 13 | if ( this[0].parentNode ) { 14 | wrap.insertBefore( this[0] ); 15 | } 16 | 17 | wrap.map(function() { 18 | var elem = this; 19 | 20 | while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { 21 | elem = elem.firstChild; 22 | } 23 | 24 | return elem; 25 | }).append( this ); 26 | } 27 | 28 | return this; 29 | }, 30 | 31 | wrapInner: function( html ) { 32 | if ( jQuery.isFunction( html ) ) { 33 | return this.each(function(i) { 34 | jQuery(this).wrapInner( html.call(this, i) ); 35 | }); 36 | } 37 | 38 | return this.each(function() { 39 | var self = jQuery( this ), 40 | contents = self.contents(); 41 | 42 | if ( contents.length ) { 43 | contents.wrapAll( html ); 44 | 45 | } else { 46 | self.append( html ); 47 | } 48 | }); 49 | }, 50 | 51 | wrap: function( html ) { 52 | var isFunction = jQuery.isFunction( html ); 53 | 54 | return this.each(function(i) { 55 | jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); 56 | }); 57 | }, 58 | 59 | unwrap: function() { 60 | return this.parent().each(function() { 61 | if ( !jQuery.nodeName( this, "body" ) ) { 62 | jQuery( this ).replaceWith( this.childNodes ); 63 | } 64 | }).end(); 65 | } 66 | }); 67 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/.jshintignore: -------------------------------------------------------------------------------- 1 | qunit/ 2 | data/badjson.js 3 | data/jquery-1.9.1.ajax_xhr.min.js 4 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "boss": true, 3 | "curly": true, 4 | "eqeqeq": true, 5 | "eqnull": true, 6 | "expr": true, 7 | "immed": true, 8 | "noarg": true, 9 | "onevar": true, 10 | "quotmark": "double", 11 | "smarttabs": true, 12 | "trailing": true, 13 | "undef": true, 14 | "unused": true, 15 | 16 | "evil": true, 17 | "sub": true, 18 | 19 | "browser": true, 20 | "devel": true, 21 | "wsh": true, 22 | 23 | "predef": [ 24 | "DOMParser", 25 | "jQuery", 26 | "QUnit", 27 | "module", 28 | "ok", 29 | "equal", 30 | "test", 31 | "asyncTest", 32 | "notEqual", 33 | "deepEqual", 34 | "strictEqual", 35 | "notStrictEqual", 36 | "start", 37 | "stop", 38 | "expect", 39 | "raises", 40 | "ajaxTest", 41 | "testIframe", 42 | "testIframeWithCallback", 43 | "createDashboardXML", 44 | "createXMLFragment", 45 | "moduleTeardown", 46 | "testFoo", 47 | "url", 48 | "t", 49 | "q", 50 | "amdDefined", 51 | "fireNative", 52 | "Globals", 53 | "hasPHP", 54 | "isLocal", 55 | "originaljQuery", 56 | "$", 57 | "original$", 58 | "externalHost" 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/1x1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/book/bower_components/jquery/test/data/1x1.jpg -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/ajax/unreleasedXHR.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Attempt to block tests because of dangling XHR requests (IE) 6 | 7 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/atom+xml.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/badcall.js: -------------------------------------------------------------------------------- 1 | undefined(); 2 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/badjson.js: -------------------------------------------------------------------------------- 1 | {bad: toTheBone} 2 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/cleanScript.html: -------------------------------------------------------------------------------- 1 | 6 | 11 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/core/cc_on.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/dashboard.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/dimensions/documentLarge.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 13 |
    14 | 15 |
    16 | 17 | 18 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/dimensions/documentSmall.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 17 |
    18 | 19 |
    20 | 21 | 22 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/echoData.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/echoQuery.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/errorWithJSON.php: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/evalScript.php: -------------------------------------------------------------------------------- 1 | ok( "" === "GET", "request method is " ); -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/event/focusElem.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | .focus() (activeElement access #13393) 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/event/longLoadScript.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/event/promiseReady.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test case for jQuery ticket #11470 6 | 7 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/event/syncReady.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test case for jQuery ticket #10067 6 | 7 | 8 | 9 | 10 | 15 | 16 | 20 | 21 |
    22 | 23 | 24 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/headers.php: -------------------------------------------------------------------------------- 1 | $value ) { 10 | 11 | $key = str_replace( "_" , "-" , substr( $key , 0 , 5 ) == "HTTP_" ? substr( $key , 5 ) : $key ); 12 | $headers[ $key ] = $value; 13 | 14 | } 15 | 16 | foreach( explode( "_" , $_GET[ "keys" ] ) as $key ) { 17 | echo "$key: " . @$headers[ strtoupper( $key ) ] . "\n"; 18 | } 19 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/if_modified_since.php: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | iframe 4 | 5 | 6 |
    span text
    7 | 8 | 9 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/json.php: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/json_obj.js: -------------------------------------------------------------------------------- 1 | { "data": {"lang": "en", "length": 25} } 2 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/jsonp.php: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/manipulation/iframe-denied.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | body 6 | 7 | 8 |
    9 | 10 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/name.html: -------------------------------------------------------------------------------- 1 | ERROR 2 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/name.php: -------------------------------------------------------------------------------- 1 | $xml$result"; 12 | die(); 13 | } 14 | $name = $_REQUEST['name']; 15 | if($name == 'foo') { 16 | echo "bar"; 17 | die(); 18 | } else if($name == 'peter') { 19 | echo "pan"; 20 | die(); 21 | } 22 | 23 | echo 'ERROR '; 24 | ?> -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/nocontent.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/offset/absolute.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | absolute 7 | 18 | 19 | 29 | 30 | 31 |
    absolute-1 32 |
    absolute-1-1 33 |
    absolute-1-1-1
    34 |
    35 |
    36 |
    absolute-2
    37 |
    Has absolute position but no values set for the location ('auto').
    38 |
    39 |

    Click the white box to move the marker to it. Clicking the box also changes the position to absolute (if not already) and sets the position according to the position method.

    40 | 41 | 42 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/offset/body.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | body 7 | 12 | 13 | 21 | 22 | 23 |
    24 |
    25 | 26 | 27 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/offset/fixed.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | fixed 7 | 15 | 16 | 25 | 26 | 27 |
    28 |
    29 |
    30 |
    31 |
    32 |

    Click the white box to move the marker to it.

    33 | 34 | 35 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/offset/relative.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | relative 7 | 13 | 14 | 24 | 25 | 26 |
    27 |
    28 |
    29 |

    Click the white box to move the marker to it. Clicking the box also changes the position to absolute (if not already) and sets the position according to the position method.

    30 | 31 | 32 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/offset/scroll.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | scroll 7 | 16 | 17 | 28 | 29 | 30 |
    31 |
    32 |
    33 |
    34 |
    35 |
    36 |
    37 |

    Click the white box to move the marker to it.

    38 | 39 | 40 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/offset/static.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | static 7 | 13 | 14 | 24 | 25 | 26 |
    27 |
    28 |
    29 |

    Click the white box to move the marker to it. Clicking the box also changes the position to absolute (if not already) and sets the position according to the position method.

    30 | 31 | 32 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/offset/table.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | table 7 | 13 | 14 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
    th-1th-2th-3
    td-1td-2td-3
    40 |
    41 |

    Click the white box to move the marker to it.

    42 | 43 | 44 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/params_html.php: -------------------------------------------------------------------------------- 1 |
    2 | $value ) 4 | echo "$value"; 5 | ?> 6 |
    7 |
    8 | $value ) 10 | echo "$value"; 11 | ?> 12 |
    -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/readywaitasset.js: -------------------------------------------------------------------------------- 1 | var delayedMessage = "It worked!"; 2 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/readywaitloader.js: -------------------------------------------------------------------------------- 1 | // Simple script loader that uses jQuery.readyWait via jQuery.holdReady() 2 | 3 | //Hold on jQuery! 4 | jQuery.holdReady(true); 5 | 6 | var readyRegExp = /^(complete|loaded)$/; 7 | 8 | function assetLoaded( evt ){ 9 | var node = evt.currentTarget || evt.srcElement; 10 | if ( evt.type === "load" || readyRegExp.test(node.readyState) ) { 11 | jQuery.holdReady(false); 12 | } 13 | } 14 | 15 | setTimeout( function() { 16 | var script = document.createElement("script"); 17 | script.type = "text/javascript"; 18 | if ( script.addEventListener ) { 19 | script.addEventListener( "load", assetLoaded, false ); 20 | } else { 21 | script.attachEvent( "onreadystatechange", assetLoaded ); 22 | } 23 | script.src = "data/readywaitasset.js"; 24 | document.getElementsByTagName("head")[0].appendChild(script); 25 | }, 2000 ); 26 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/script.php: -------------------------------------------------------------------------------- 1 | 11 | ok( true, "Script executed correctly." ); 12 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/selector/html5_selector.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jQuery selector - attributes 6 | 7 | 8 | 9 | 12 | 13 | 19 | 20 | 21 | 23 | 24 |
    26 | 27 |
    31 | 37 | 39 |
    40 | 41 | 42 | 44 |
    45 | 46 | 49 | 50 | 52 | 53 |
      55 | 56 |
      58 | 59 |
      61 | 62 | 73 | 74 | 76 | 77 | 82 | 83 | 84 | 87 | 88 | 89 | 93 | 94 | 100 | 101 |
      103 |
      Term
      This is the first definition in compact format.
      104 |
      Term
      This is the second definition in compact format.
      105 |
      106 | 107 | 109 | 110 | Scrolling text (non-standard) 113 | 114 | 115 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/selector/sizzle_cache.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jQuery selector - sizzle cache 6 | 7 | 8 | 14 | 15 | 16 | 17 |
      18 | Worlds collide 19 |
      20 | 21 | 22 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/statusText.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/support/bodyBackground.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | 19 |
      20 | 21 |
      22 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/support/boxSizing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/support/csp.js: -------------------------------------------------------------------------------- 1 | jQuery(function() { 2 | parent.iframeCallback( jQuery.support ); 3 | }); 4 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/support/csp.php: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | CSP Test Page 16 | 17 | 18 | 19 | 20 |

      CSP Test Page

      21 | 22 | 23 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/support/shrinkWrapBlocks.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 13 | 14 |
      15 | 16 |
      17 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/support/testElementCrash.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/test.html: -------------------------------------------------------------------------------- 1 | html text
      2 | 6 | 7 | blabla 8 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/test.js: -------------------------------------------------------------------------------- 1 | this.testBar = "bar"; 2 | jQuery("#ap").html("bar"); 3 | ok( true, "test.js executed"); 4 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/test.php: -------------------------------------------------------------------------------- 1 | html text
      2 | 6 | 7 | blabla -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/test2.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/test3.html: -------------------------------------------------------------------------------- 1 |
      This is a user
      2 |
      This is a user
      3 |
      This is a teacher
      4 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/testsuite.css: -------------------------------------------------------------------------------- 1 | /* for testing opacity set in styles in IE */ 2 | ol#empty { 3 | opacity: 0; 4 | filter:Alpha(opacity=0) progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffff0000', EndColorStr='#ffffffff'); 5 | } 6 | 7 | div#fx-tests h4 { 8 | background: red; 9 | } 10 | 11 | div#fx-tests h4.pass { 12 | background: green; 13 | } 14 | 15 | div#fx-tests div.box { 16 | background: red; 17 | overflow: hidden; 18 | border: 2px solid #000; 19 | } 20 | 21 | div#fx-tests div.overflow { 22 | overflow: visible; 23 | } 24 | 25 | div.inline { 26 | display: inline; 27 | } 28 | 29 | div.autoheight { 30 | height: auto; 31 | } 32 | 33 | div.autowidth { 34 | width: auto; 35 | } 36 | 37 | div.autoopacity { 38 | opacity: auto; 39 | } 40 | 41 | div.largewidth { 42 | width: 100px; 43 | } 44 | 45 | div.largeheight { 46 | height: 100px; 47 | } 48 | 49 | div.largeopacity { 50 | filter: progid:DXImageTransform.Microsoft.Alpha(opacity=100); 51 | } 52 | 53 | div.medwidth { 54 | width: 50px; 55 | } 56 | 57 | div.medheight { 58 | height: 50px; 59 | } 60 | 61 | div.medopacity { 62 | opacity: 0.5; 63 | filter: progid:DXImageTransform.Microsoft.Alpha(opacity=50); 64 | } 65 | 66 | div.nowidth { 67 | width: 0px; 68 | } 69 | 70 | div.noheight { 71 | height: 0px; 72 | } 73 | 74 | div.noopacity { 75 | opacity: 0; 76 | filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0); 77 | } 78 | 79 | div.hidden { 80 | display: none; 81 | } 82 | 83 | div#fx-tests div.widewidth { 84 | background-repeat: repeat-x; 85 | } 86 | 87 | div#fx-tests div.wideheight { 88 | background-repeat: repeat-y; 89 | } 90 | 91 | div#fx-tests div.widewidth.wideheight { 92 | background-repeat: repeat; 93 | } 94 | 95 | div#fx-tests div.noback { 96 | background-image: none; 97 | } 98 | 99 | .chain-test, 100 | .chain-test div { 101 | width: 100px; 102 | height: 20px; 103 | position: relative; 104 | float: left; 105 | } 106 | .chain-test div { 107 | position: absolute; 108 | top: 0; 109 | left: 0; 110 | } 111 | 112 | .chain-test { 113 | background: red; 114 | } 115 | .chain-test div { 116 | background: green; 117 | } 118 | 119 | .chain-test-out { 120 | background: green; 121 | } 122 | .chain-test-out div { 123 | background: red; 124 | display: none; 125 | } 126 | 127 | /* tests to ensure jQuery can determine the native display mode of elements 128 | that have been set as display: none in stylesheets */ 129 | div#show-tests * { display: none; } 130 | 131 | #nothiddendiv { font-size: 16px; } 132 | #nothiddendivchild.em { font-size: 2em; } 133 | #nothiddendivchild.prct { font-size: 150%; } 134 | 135 | /* For testing type on vml in IE #7071 */ 136 | v\:oval { behavior:url(#default#VML); display:inline-block; } 137 | 138 | /* 8099 changes to default styles are read correctly */ 139 | tt { display: none; } 140 | sup { display: none; } 141 | dfn { display: none; } 142 | 143 | /* #9239 Attach a background to the body( avoid crashes in removing the test element in support ) */ 144 | body, div { background: url(http://static.jquery.com/files/rocker/images/logo_jquery_215x53.gif) no-repeat -1000px 0; } 145 | 146 | /* #6652 REMOVE FILTER:ALPHA(OPACITY=100) AFTER ANIMATION */ 147 | #t6652 div { filter: alpha(opacity=50); } 148 | 149 | /* #10501 */ 150 | section { background:#f0f; display:block; } 151 | 152 | /* #11971 */ 153 | #foo { background: url(1x1.jpg) right bottom no-repeat; } 154 | 155 | #display { display: list-item !important; } 156 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/text.php: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet 2 | consectetuer adipiscing elit 3 | Sed lorem leo 4 | lorem leo consectetuer adipiscing elit 5 | Sed lorem leo 6 | rhoncus sit amet 7 | elementum at 8 | bibendum at, eros 9 | Cras at mi et tortor egestas vestibulum 10 | sed Cras at mi vestibulum 11 | Phasellus sed felis sit amet 12 | orci dapibus semper. 13 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/with_fries.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 1 14 | 15 | 16 | 17 | 18 | foo 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/data/with_fries_over_jsonp.php: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/hovertest.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hover tests 4 | 5 | 32 | 33 | 34 |

      Hover (mouse{over,out,enter,leave}) Tests

      35 |

      Be sure to try moving the mouse out of the browser via the left side on each test.

      36 |
      37 | 38 |
      39 |
      40 | 41 | .hover() in/out: 0 / 0 42 |
      43 |
      44 | Mouse over here should NOT trigger the counter. 45 |
      46 |
      47 |
      48 |
      49 | 50 | Live enter/leave: 0 / 0 51 |
      52 |
      53 | Mouse over here should NOT trigger the counter. 54 |
      55 |
      56 |
      57 |
      58 | 59 | Delegated enter/leave: 0 / 0 60 |
      61 |
      62 | Mouse over here should NOT trigger the counter. 63 |
      64 |
      65 | 66 |
      67 |
      68 | 69 | Bind over/out: 0 / 0 70 |
      71 |
      72 | Mouse over here SHOULD trigger the counter. 73 |
      74 |
      75 |
      76 |
      77 | 78 | Live over/out: 0 / 0 79 |
      80 |
      81 | Mouse over here SHOULD trigger the counter. 82 |
      83 |
      84 |
      85 |
      86 | 87 | Delegated over/out: 0 / 0 88 |
      89 |
      90 | Mouse over here SHOULD trigger the counter. 91 |
      92 |
      93 | 94 |
      95 | 96 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/jquery.js: -------------------------------------------------------------------------------- 1 | // Use the right jQuery source in iframe tests 2 | document.write( " 8 | 12 | 13 | 14 |

      jQuery Local File Test

      15 |

      16 | Introduction 17 |

      18 |
        19 |
      • 20 | Access this file using the "file:" protocol, 21 |
      • 22 |
      • 23 | two green "OK" strings must appear below, 24 |
      • 25 |
      • 26 | Empty local files will issue errors, it's a known limitation. 27 |
      • 28 |
      29 |

      30 | Results 31 |

      32 |
        33 |
      • 34 | Success: 35 | 36 | 37 |
      • 38 |
      • 39 | Error: 40 | 41 | 42 |
      • 43 |
      44 |

      45 | Logs: 46 |

      47 |
        48 |
      49 | 75 | 76 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/networkerror.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | jQuery Network Error Test for Firefox 14 | 15 | 18 | 19 | 36 | 37 | 38 |

      39 | jQuery Network Error Test for Firefox 40 |

      41 |
      42 | This is a test page for 43 | 44 | #8135 45 | 46 | which was reported in Firefox when accessing properties 47 | of an XMLHttpRequest object after a network error occurred. 48 |
      49 |
      Take the following steps:
      50 |
        51 |
      1. 52 | make sure you accessed this page through a web server, 53 |
      2. 54 |
      3. 55 | stop the web server, 56 |
      4. 57 |
      5. 58 | open the console, 59 |
      6. 60 |
      7. 61 | click this 62 | 63 | , 64 |
      8. 65 |
      9. 66 | wait for both requests to fail. 67 |
      10. 68 |
      69 |
      70 | Test passes if you get two log lines: 71 |
        72 |
      • 73 | the first starting with "abort", 74 |
      • 75 |
      • 76 | the second starting with "complete", 77 |
      • 78 |
      79 |
      80 |
      81 | Test fails if the browser notifies an exception. 82 |
      83 | 84 | 85 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/readywait.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | jQuery.holdReady Test 11 | 12 | 17 | 18 | 19 | 21 | 22 | 23 | 34 | 35 | 36 |

      37 | jQuery.holdReady Test 38 |

      39 |

      40 | This is a test page for jQuery.readyWait and jQuery.holdReady, 41 | see 42 | #6781 43 | and 44 | #8803. 45 |

      46 |

      47 | Test for jQuery.holdReady, which can be used 48 | by plugins and other scripts to indicate something 49 | important to the page is still loading and needs 50 | to block the DOM ready callbacks that are registered 51 | with jQuery. 52 |

      53 |

      54 | Script loaders are the most likely kind of script 55 | to use jQuery.holdReady, but it could be used by 56 | other things like a script that loads a CSS file 57 | and wants to pause the DOM ready callbacks. 58 |

      59 |

      60 | Expected Result: The text 61 | It Worked! 62 | appears below after about 2 seconds. 63 |

      64 |

      65 | If there is an error in the console, 66 | or the text does not show up, then the test failed. 67 |

      68 |
      69 | 70 | 71 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/unit/deprecated.js: -------------------------------------------------------------------------------- 1 | module("deprecated", { teardown: moduleTeardown }); 2 | 3 | if ( jQuery.fn.size ) { 4 | test("size()", function() { 5 | expect(1); 6 | equal( jQuery("#qunit-fixture p").size(), 6, "Get Number of Elements Found" ); 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/unit/exports.js: -------------------------------------------------------------------------------- 1 | module("exports", { teardown: moduleTeardown }); 2 | 3 | test("amdModule", function() { 4 | expect(1); 5 | 6 | equal( jQuery, amdDefined, "Make sure defined module matches jQuery" ); 7 | }); 8 | -------------------------------------------------------------------------------- /book/bower_components/jquery/test/xhtml.php: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /book/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/book/favicon.ico -------------------------------------------------------------------------------- /book/images/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/book/images/base.png -------------------------------------------------------------------------------- /book/images/ns1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/book/images/ns1.png -------------------------------------------------------------------------------- /book/img/base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/book/img/base.png -------------------------------------------------------------------------------- /book/img/ns1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/book/img/ns1.png -------------------------------------------------------------------------------- /book/metadata.xml: -------------------------------------------------------------------------------- 1 | Essential JavaScript Design Patterns 2 | Addy Osmani 3 | Creative Commons Attribution Non-Commercial Share Alike 3.0 4 | en-US 5 | -------------------------------------------------------------------------------- /book/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /book/scripts/vendor/shBrushJScript.js: -------------------------------------------------------------------------------- 1 | ;(function() 2 | { 3 | // CommonJS 4 | SyntaxHighlighter = SyntaxHighlighter || (typeof require !== 'undefined'? require('shCore').SyntaxHighlighter : null); 5 | 6 | function Brush() 7 | { 8 | var keywords = 'break case catch class continue ' + 9 | 'default delete do else enum export extends false ' + 10 | 'for function if implements import in instanceof ' + 11 | 'interface let new null package private protected ' + 12 | 'static return super switch ' + 13 | 'this throw true try typeof var while with yield'; 14 | 15 | var r = SyntaxHighlighter.regexLib; 16 | 17 | this.regexList = [ 18 | { regex: r.multiLineDoubleQuotedString, css: 'string' }, // double quoted strings 19 | { regex: r.multiLineSingleQuotedString, css: 'string' }, // single quoted strings 20 | { regex: r.singleLineCComments, css: 'comments' }, // one line comments 21 | { regex: r.multiLineCComments, css: 'comments' }, // multiline comments 22 | { regex: /\s*#.*/gm, css: 'preprocessor' }, // preprocessor tags like #region and #endregion 23 | { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keywords 24 | ]; 25 | 26 | this.forHtmlScript(r.scriptScriptTags); 27 | }; 28 | 29 | Brush.prototype = new SyntaxHighlighter.Highlighter(); 30 | Brush.aliases = ['js', 'jscript', 'javascript']; 31 | 32 | SyntaxHighlighter.brushes.JScript = Brush; 33 | 34 | // CommonJS 35 | typeof(exports) != 'undefined' ? exports.Brush = Brush : null; 36 | })(); 37 | -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/0-design-pattern-categorization.es2015.js: -------------------------------------------------------------------------------- 1 | //*******************************************************// 2 | // A brief note on classes 3 | //*******************************************************// 4 | 5 | // Section contains description of ES2015, but not use it. 6 | // I suggest remove the description and put the new examples. 7 | 8 | //********************** Snippet 1 **********************// 9 | 10 | // A car "class" 11 | 12 | // [ES2015+] Below we used new class declaration, using keyword class 13 | // [ES2015+] We used new constructor method and method declaration 14 | // [ES2015+] Classes are syntactic sugar over JavaScript's prototype-based inheritance 15 | // [ES2015+] We used new template literals for string interpolation 16 | class Car { 17 | constructor(model) { 18 | this.model = model; 19 | this.color = 'silver'; 20 | this.year = '2012'; 21 | } 22 | 23 | getInfo() { 24 | return `${this.model} ${this.year}`; 25 | } 26 | } 27 | 28 | //********************** Snippet 2 **********************// 29 | 30 | // Usage: 31 | 32 | // [ES2015+] We used new keyword const for immutable constant declaration 33 | const myCar = new Car('ford'); 34 | 35 | myCar.year = '2010'; 36 | 37 | console.log(myCar.getInfo()); 38 | 39 | // Here the link on Stoyan Stefanov's post, it's a good post. 40 | // But more modern data can be obtained here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes 41 | -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/0-design-pattern-categorization.es5.js: -------------------------------------------------------------------------------- 1 | //*******************************************************// 2 | // A brief note on classes 3 | //*******************************************************// 4 | 5 | //********************** Snippet 1 **********************// 6 | 7 | // A car "class" 8 | function Car( model ) { 9 | 10 | this.model = model; 11 | this.color = "silver"; 12 | this.year = "2012"; 13 | 14 | this.getInfo = function () { 15 | return this.model + " " + this.year; 16 | }; 17 | 18 | } 19 | 20 | //********************** Snippet 2 **********************// 21 | 22 | var myCar = new Car("ford"); 23 | 24 | myCar.year = "2010"; 25 | 26 | console.log( myCar.getInfo() ); -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/1-the-constructor-pattern.es5.js: -------------------------------------------------------------------------------- 1 | //*******************************************************// 2 | // Object Creation 3 | //*******************************************************// 4 | 5 | //********************** Snippet 1 **********************// 6 | 7 | // Each of the following options will create a new empty object: 8 | 9 | var newObject = {}; 10 | 11 | // or 12 | var newObject = Object.create( Object.prototype ); 13 | 14 | // or 15 | var newObject = new Object(); 16 | 17 | 18 | //********************** Snippet 2 **********************// 19 | 20 | // ECMAScript 3 compatible approaches 21 | 22 | // 1. Dot syntax 23 | 24 | // Set properties 25 | newObject.someKey = "Hello World"; 26 | 27 | // Get properties 28 | var value = newObject.someKey; 29 | 30 | 31 | 32 | // 2. Square bracket syntax 33 | 34 | // Set properties 35 | newObject["someKey"] = "Hello World"; 36 | 37 | // Get properties 38 | var value = newObject["someKey"]; 39 | 40 | 41 | 42 | // ECMAScript 5 only compatible approaches 43 | // For more information see: http://kangax.github.com/es5-compat-table/ 44 | 45 | // 3. Object.defineProperty 46 | 47 | // Set properties 48 | Object.defineProperty( newObject, "someKey", { 49 | value: "for more control of the property's behavior", 50 | writable: true, 51 | enumerable: true, 52 | configurable: true 53 | }); 54 | 55 | // If the above feels a little difficult to read, a short-hand could 56 | // be written as follows: 57 | 58 | var defineProp = function ( obj, key, value ){ 59 | var config = { 60 | value: value, 61 | writable: true, 62 | enumerable: true, 63 | configurable: true 64 | }; 65 | Object.defineProperty( obj, key, config ); 66 | }; 67 | 68 | // To use, we then create a new empty "person" object 69 | var person = Object.create( Object.prototype ); 70 | 71 | // Populate the object with properties 72 | defineProp( person, "car", "Delorean" ); 73 | defineProp( person, "dateOfBirth", "1981" ); 74 | defineProp( person, "hasBeard", false ); 75 | 76 | console.log(person); 77 | // Outputs: Object {car: "Delorean", dateOfBirth: "1981", hasBeard: false} 78 | 79 | 80 | // 4. Object.defineProperties 81 | 82 | // Set properties 83 | Object.defineProperties( newObject, { 84 | 85 | "someKey": { 86 | value: "Hello World", 87 | writable: true 88 | }, 89 | 90 | "anotherKey": { 91 | value: "Foo bar", 92 | writable: false 93 | } 94 | 95 | }); 96 | 97 | // Getting properties for 3. and 4. can be done using any of the 98 | // options in 1. and 2. 99 | 100 | 101 | //********************** Snippet 3 **********************// 102 | 103 | // Usage: 104 | 105 | // Create a race car driver that inherits from the person object 106 | var driver = Object.create( person ); 107 | 108 | // Set some properties for the driver 109 | defineProp(driver, "topSpeed", "100mph"); 110 | 111 | // Get an inherited property (1981) 112 | console.log( driver.dateOfBirth ); 113 | 114 | // Get the property we set (100mph) 115 | console.log( driver.topSpeed ); 116 | 117 | 118 | //*******************************************************// 119 | // Basic Constructors 120 | //*******************************************************// 121 | 122 | //********************** Snippet 1 **********************// 123 | 124 | function Car( model, year, miles ) { 125 | 126 | this.model = model; 127 | this.year = year; 128 | this.miles = miles; 129 | 130 | this.toString = function () { 131 | return this.model + " has done " + this.miles + " miles"; 132 | }; 133 | } 134 | 135 | // Usage: 136 | 137 | // We can create new instances of the car 138 | var civic = new Car( "Honda Civic", 2009, 20000 ); 139 | var mondeo = new Car( "Ford Mondeo", 2010, 5000 ); 140 | 141 | // and then open our browser console to view the 142 | // output of the toString() method being called on 143 | // these objects 144 | console.log( civic.toString() ); 145 | console.log( mondeo.toString() ); 146 | 147 | //*******************************************************// 148 | // Constructors With Prototypes 149 | //*******************************************************// 150 | 151 | //********************** Snippet 1 **********************// 152 | 153 | function Car( model, year, miles ) { 154 | 155 | this.model = model; 156 | this.year = year; 157 | this.miles = miles; 158 | 159 | } 160 | 161 | 162 | // Note here that we are using Object.prototype.newMethod rather than 163 | // Object.prototype so as to avoid redefining the prototype object 164 | Car.prototype.toString = function () { 165 | return this.model + " has done " + this.miles + " miles"; 166 | }; 167 | 168 | // Usage: 169 | 170 | var civic = new Car( "Honda Civic", 2009, 20000 ); 171 | var mondeo = new Car( "Ford Mondeo", 2010, 5000 ); 172 | 173 | console.log( civic.toString() ); 174 | console.log( mondeo.toString() ); -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/11-the-mixin-pattern.es2015-2.js: -------------------------------------------------------------------------------- 1 | //*******************************************************// 2 | // Mixins 3 | //*******************************************************// 4 | 5 | //********************** Snippet 1 **********************// 6 | // [ES2015+] We used new keyword const for immutable constant declaration 7 | // [ES2015+] We used new method declaration 8 | // [ES2015+] We used new arrow function syntax 9 | // [ES2015+] Below we used new class declaration, using keyword class 10 | // [ES2015+] Class can be used as an expression as well as a statement. As an expression it returns a new class each time it's evaluated. 11 | // [ES2015+] The extends keyword is used to create a class which is a child of another class. 12 | // [ES2015+] The extends clause accepts arbitrary expressions that return classes or constructors 13 | // [ES2015+] All we need to define a mixin is a function that accepts a superclass and creates a new subclass from it, like this: 14 | 15 | const MyMixins = superclass => 16 | class extends superclass { 17 | moveUp() { 18 | console.log('move up'); 19 | } 20 | moveDown() { 21 | console.log('move down'); 22 | } 23 | stop() { 24 | console.log('stop! in the name of love!'); 25 | } 26 | }; 27 | 28 | //********************** Snippet 2 **********************// 29 | // [ES2015+] Below we used new class declaration, using keyword class 30 | // [ES2015+] We used new constructor method and method declaration 31 | // [ES2015+] We used new arrow function syntax 32 | // [ES2015+] We have new pattern implementation with new inheritance 33 | 34 | // A skeleton carAnimator constructor 35 | class CarAnimator { 36 | moveLeft() { 37 | console.log('move left'); 38 | } 39 | } 40 | // A skeleton personAnimator constructor 41 | class PersonAnimator { 42 | moveRandomly() { 43 | /*..*/ 44 | } 45 | } 46 | 47 | // [ES2015+] Then we can use it in an extends clause like this: 48 | class MyAnimator extends MyMixins(CarAnimator) {} 49 | 50 | // Create a new instance of carAnimator 51 | const myAnimator = new MyAnimator(); 52 | myAnimator.moveLeft(); 53 | myAnimator.moveDown(); 54 | myAnimator.stop(); 55 | 56 | // Outputs: 57 | // move left 58 | // move down 59 | // stop! in the name of love! 60 | 61 | //********************** Snippet 3 **********************// 62 | // [ES2015+] Below we used new class declaration, using keyword class 63 | // [ES2015+] We used new constructor method and method declaration 64 | // [ES2015+] Classes are syntactic sugar over JavaScript's prototype-based inheritance 65 | // [ES2015+] The extends keyword is used to create a class which is a child of another class. 66 | // [ES2015+] We used new keyword const for immutable constant declaration 67 | // [ES2015+] We used new arrow function syntax 68 | 69 | // Define a simple Car constructor 70 | class Car { 71 | constructor({ model, color }) { 72 | this.model = model || 'no model provided'; 73 | this.color = color || 'no colour provided'; 74 | } 75 | } 76 | 77 | // Mixin 78 | const Mixin = superclass => 79 | class extends superclass { 80 | driveForward() { 81 | console.log('drive forward'); 82 | } 83 | driveBackward() { 84 | console.log('drive backward'); 85 | } 86 | driveSideways() { 87 | console.log('drive sideways'); 88 | } 89 | }; 90 | 91 | class MyCar extends Mixin(Car) {} 92 | 93 | // Create a new Car 94 | const myCar = new MyCar({ 95 | model: 'Ford Escort', 96 | color: 'blue', 97 | }); 98 | 99 | // Test to make sure we now have access to the methods 100 | myCar.driveForward(); 101 | myCar.driveBackward(); 102 | 103 | // Outputs: 104 | // drive forward 105 | // drive backward 106 | 107 | const mySportCar = new MyCar({ 108 | model: 'Porsche', 109 | color: 'red', 110 | }); 111 | 112 | mySportsCar.driveSideways(); 113 | 114 | // Outputs: 115 | // drive sideways 116 | -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/3-the-revealing-module-pattern.es2015.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | // [ES2015+] We used new template literals for string interpolation 3 | // [ES2015+] We used new keyword const for immutable constant declaration 4 | // [SE2015+] We used new keyword let, which declares a block scope local variable 5 | // [ES2015+] We used new arrow function syntax 6 | // [ES2015+] We have new pattern implementation with new keywords import and export 7 | 8 | let privateVar = 'Ben Cherry'; 9 | const publicVar = 'Hey there!'; 10 | 11 | const privateFunction = () => { 12 | console.log(`Name:${privateVar}`); 13 | }; 14 | 15 | // [ES2015+] Parentheses are optional when there's only one parameter 16 | const publicSetName = strName => { 17 | privateVar = strName; 18 | }; 19 | 20 | const publicGetName = () => { 21 | privateFunction(); 22 | }; 23 | 24 | // Reveal public pointers to 25 | // private functions and properties 26 | const myRevealingModule = { 27 | setName: publicSetName, 28 | greeting: publicVar, 29 | getName: publicGetName, 30 | }; 31 | 32 | // [ES2015+] Default export module, without name 33 | export default myRevealingModule; 34 | 35 | // Usage: 36 | // [ES2015+] The import statement is used to import bindings which are exported by another module. 37 | import myRevealingModule from './myRevealingModule'; 38 | 39 | myRevealingModule.setName('Paul Kinlan'); 40 | 41 | 42 | //********************** Snippet 2 **********************// 43 | // [ES2015+] We used new keyword const for immutable constant declaration 44 | // [SE2015+] We used new keyword let, which declares a block scope local variable 45 | // [ES2015+] We used new arrow function syntax 46 | // [ES2015+] We have new pattern implementation with new keywords import and export 47 | 48 | let privateCounter = 0; 49 | 50 | const privateFunction = () => { 51 | privateCounter++; 52 | } 53 | 54 | const publicFunction = () => { 55 | publicIncrement(); 56 | } 57 | 58 | const publicIncrement = () => { 59 | privateFunction(); 60 | } 61 | 62 | // [ES2015+] Equivalent to: => { return privateCounter; } 63 | const publicGetCount = () => privateCounter; 64 | 65 | // Reveal public pointers to 66 | // private functions and properties 67 | const myRevealingModule = { 68 | start: publicFunction, 69 | increment: publicIncrement, 70 | count: publicGetCount 71 | }; 72 | 73 | // [ES2015+] Default export module, without name 74 | export default myRevealingModule; 75 | 76 | // Usage: 77 | // [ES2015+] The import statement is used to import bindings which are exported by another module. 78 | import myRevealingModule from './myRevealingModule'; 79 | 80 | myRevealingModule.start(); 81 | -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/3-the-revealing-module-pattern.es5.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | 3 | var myRevealingModule = (function () { 4 | 5 | var privateVar = "Ben Cherry", 6 | publicVar = "Hey there!"; 7 | 8 | function privateFunction() { 9 | console.log( "Name:" + privateVar ); 10 | } 11 | 12 | function publicSetName( strName ) { 13 | privateVar = strName; 14 | } 15 | 16 | function publicGetName() { 17 | privateFunction(); 18 | } 19 | 20 | 21 | // Reveal public pointers to 22 | // private functions and properties 23 | 24 | return { 25 | setName: publicSetName, 26 | greeting: publicVar, 27 | getName: publicGetName 28 | }; 29 | 30 | })(); 31 | 32 | myRevealingModule.setName( "Paul Kinlan" ); 33 | 34 | //********************** Snippet 2 **********************// 35 | 36 | var myRevealingModule = (function () { 37 | 38 | var privateCounter = 0; 39 | 40 | function privateFunction() { 41 | privateCounter++; 42 | } 43 | 44 | function publicFunction() { 45 | publicIncrement(); 46 | } 47 | 48 | function publicIncrement() { 49 | privateFunction(); 50 | } 51 | 52 | function publicGetCount(){ 53 | return privateCounter; 54 | } 55 | 56 | // Reveal public pointers to 57 | // private functions and properties 58 | 59 | return { 60 | start: publicFunction, 61 | increment: publicIncrement, 62 | count: publicGetCount 63 | }; 64 | 65 | })(); 66 | 67 | myRevealingModule.start(); 68 | 69 | -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/4-the-singleton-pattern.es5.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | 3 | var mySingleton = (function () { 4 | 5 | // Instance stores a reference to the Singleton 6 | var instance; 7 | 8 | function init() { 9 | 10 | // Singleton 11 | 12 | // Private methods and variables 13 | function privateMethod(){ 14 | console.log( "I am private" ); 15 | } 16 | 17 | var privateVariable = "Im also private"; 18 | 19 | var privateRandomNumber = Math.random(); 20 | 21 | return { 22 | 23 | // Public methods and variables 24 | publicMethod: function () { 25 | console.log( "The public can see me!" ); 26 | }, 27 | 28 | publicProperty: "I am also public", 29 | 30 | getRandomNumber: function() { 31 | return privateRandomNumber; 32 | } 33 | 34 | }; 35 | 36 | }; 37 | 38 | return { 39 | 40 | // Get the Singleton instance if one exists 41 | // or create one if it doesn't 42 | getInstance: function () { 43 | 44 | if ( !instance ) { 45 | instance = init(); 46 | } 47 | 48 | return instance; 49 | } 50 | 51 | }; 52 | 53 | })(); 54 | 55 | var myBadSingleton = (function () { 56 | 57 | // Instance stores a reference to the Singleton 58 | var instance; 59 | 60 | function init() { 61 | 62 | // Singleton 63 | 64 | var privateRandomNumber = Math.random(); 65 | 66 | return { 67 | 68 | getRandomNumber: function() { 69 | return privateRandomNumber; 70 | } 71 | 72 | }; 73 | 74 | }; 75 | 76 | return { 77 | 78 | // Always create a new Singleton instance 79 | getInstance: function () { 80 | 81 | instance = init(); 82 | 83 | return instance; 84 | } 85 | 86 | }; 87 | 88 | })(); 89 | 90 | 91 | // Usage: 92 | 93 | var singleA = mySingleton.getInstance(); 94 | var singleB = mySingleton.getInstance(); 95 | console.log( singleA.getRandomNumber() === singleB.getRandomNumber() ); // true 96 | 97 | var badSingleA = myBadSingleton.getInstance(); 98 | var badSingleB = myBadSingleton.getInstance(); 99 | console.log( badSingleA.getRandomNumber() !== badSingleB.getRandomNumber() ); // true 100 | 101 | // Note: as we are working with random numbers, there is a 102 | // mathematical possibility both numbers will be the same, 103 | // however unlikely. The above example should otherwise still 104 | // be valid. 105 | 106 | //********************** Snippet 2 **********************// 107 | 108 | mySingleton.getInstance = function(){ 109 | if ( this._instance == null ) { 110 | if ( isFoo() ) { 111 | this._instance = new FooSingleton(); 112 | } else { 113 | this._instance = new BasicSingleton(); 114 | } 115 | } 116 | return this._instance; 117 | }; 118 | 119 | 120 | //********************** Snippet 3 **********************// 121 | 122 | var SingletonTester = (function () { 123 | 124 | // options: an object containing configuration options for the singleton 125 | // e.g var options = { name: "test", pointX: 5}; 126 | function Singleton( options ) { 127 | 128 | // set options to the options supplied 129 | // or an empty object if none are provided 130 | options = options || {}; 131 | 132 | // set some properties for our singleton 133 | this.name = "SingletonTester"; 134 | 135 | this.pointX = options.pointX || 6; 136 | 137 | this.pointY = options.pointY || 10; 138 | 139 | } 140 | 141 | // our instance holder 142 | var instance; 143 | 144 | // an emulation of static variables and methods 145 | var _static = { 146 | 147 | name: "SingletonTester", 148 | 149 | // Method for getting an instance. It returns 150 | // a singleton instance of a singleton object 151 | getInstance: function( options ) { 152 | if( instance === undefined ) { 153 | instance = new Singleton( options ); 154 | } 155 | 156 | return instance; 157 | 158 | } 159 | }; 160 | 161 | return _static; 162 | 163 | })(); 164 | 165 | var singletonTest = SingletonTester.getInstance({ 166 | pointX: 5 167 | }); 168 | 169 | // Log the output of pointX just to verify it is correct 170 | // Outputs: 5 171 | console.log( singletonTest.pointX ); -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/6-the-mediator-pattern.es2015.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | // [ES2015+] We used new keyword const for immutable constant declaration 3 | 4 | const mediator = {}; 5 | 6 | //********************** Snippet 2 **********************// 7 | // [ES2015+] We used new keyword const for immutable constant declaration 8 | // [ES2015+] We used new arrow function syntax 9 | 10 | const orgChart = { 11 | addNewEmployee() { 12 | // getEmployeeDetail provides a view that users interact with 13 | const employeeDetail = this.getEmployeeDetail(); 14 | 15 | // when the employee detail is complete, the mediator (the 'orgchart' object) 16 | // decides what should happen next 17 | // [ES2015+] Parentheses are optional when there is only one parameter 18 | employeeDetail.on('complete', employee => { 19 | // set up additional objects that have additional events, which are used 20 | // by the mediator to do additional things 21 | // [ES2015+] Parentheses are optional when there is only one parameter 22 | const managerSelector = this.selectManager(employee); 23 | managerSelector.on('save', employee => { 24 | employee.save(); 25 | }); 26 | }); 27 | }, 28 | 29 | // ... 30 | }; 31 | 32 | //********************** Snippet 3 **********************// 33 | // [ES2015+] We used new keyword const for immutable constant declaration 34 | // [ES2015+] Below we used new class declaration, using keyword class 35 | // [ES2015+] We used new constructor method and method declaration 36 | // [ES2015+] Classes are syntactic sugar over JavaScript's prototype-based inheritance 37 | // [ES2015+] We used new template literals for string interpolation 38 | 39 | const MenuItem = MyFrameworkView.extend({ 40 | events: { 41 | 'click .thatThing': 'clickedIt', 42 | }, 43 | 44 | clickedIt(e) { 45 | e.preventDefault(); 46 | 47 | // assume this triggers "menu:click:foo" 48 | MyFramework.trigger(`menu:click:${this.model.get('name')}`); 49 | }, 50 | }); 51 | 52 | // ... somewhere else in the app 53 | 54 | class MyWorkflow { 55 | constructor() { 56 | MyFramework.on('menu:click:foo', this.doStuff, this); 57 | } 58 | 59 | // [ES2015+] The static keyword defines a static method for a class. 60 | // [ES2015+] Static methods are called without instantiating their class and cannot be called through a class instance. 61 | // [ES2015+] Static methods are often used to create utility functions for an application. 62 | static doStuff() { 63 | // instantiate multiple objects here. 64 | // set up event handlers for those objects. 65 | // coordinate all of the objects into a meaningful workflow. 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/6-the-mediator-pattern.es5.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | 3 | var mediator = {}; 4 | 5 | //********************** Snippet 2 **********************// 6 | 7 | var orgChart = { 8 | 9 | addNewEmployee: function(){ 10 | 11 | // getEmployeeDetail provides a view that users interact with 12 | var employeeDetail = this.getEmployeeDetail(); 13 | 14 | // when the employee detail is complete, the mediator (the 'orgchart' object) 15 | // decides what should happen next 16 | employeeDetail.on("complete", function(employee){ 17 | 18 | // set up additional objects that have additional events, which are used 19 | // by the mediator to do additional things 20 | var managerSelector = this.selectManager(employee); 21 | managerSelector.on("save", function(employee){ 22 | employee.save(); 23 | }); 24 | 25 | }); 26 | }, 27 | 28 | // ... 29 | } 30 | 31 | //********************** Snippet 3 **********************// 32 | 33 | var MenuItem = MyFrameworkView.extend({ 34 | 35 | events: { 36 | "click .thatThing": "clickedIt" 37 | }, 38 | 39 | clickedIt: function(e){ 40 | e.preventDefault(); 41 | 42 | // assume this triggers "menu:click:foo" 43 | MyFramework.trigger("menu:click:" + this.model.get("name")); 44 | } 45 | 46 | }); 47 | 48 | // ... somewhere else in the app 49 | 50 | var MyWorkflow = function(){ 51 | MyFramework.on("menu:click:foo", this.doStuff, this); 52 | }; 53 | 54 | MyWorkflow.prototype.doStuff = function(){ 55 | // instantiate multiple objects here. 56 | // set up event handlers for those objects. 57 | // coordinate all of the objects into a meaningful workflow. 58 | }; 59 | 60 | -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/7-the-prototype-pattern.es2015.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | // [ES2015+] We used new keyword const for immutable constant declaration 3 | 4 | const myCar = { 5 | name: 'Ford Escort', 6 | 7 | drive() { 8 | console.log("Weeee. I'm driving!"); 9 | }, 10 | 11 | panic() { 12 | console.log('Wait. How do you stop this thing?'); 13 | }, 14 | }; 15 | 16 | // Use Object.create to instantiate a new car 17 | const yourCar = Object.create(myCar); 18 | 19 | // Now we can see that one is a prototype of the other 20 | console.log(yourCar.name); 21 | 22 | //********************** Snippet 2 **********************// 23 | // [ES2015+] We used new keyword const for immutable constant declaration 24 | // [ES2015+] We used new template literals for string interpolation 25 | 26 | const vehicle = { 27 | getModel() { 28 | console.log(`The model of this vehicle is..${this.model}`); 29 | }, 30 | }; 31 | 32 | const car = Object.create(vehicle, { 33 | id: { 34 | value: MY_GLOBAL.nextId(), 35 | // writable:false, configurable:false by default 36 | enumerable: true, 37 | }, 38 | 39 | model: { 40 | value: 'Ford', 41 | enumerable: true, 42 | }, 43 | }); 44 | 45 | //********************** Snippet 3 **********************// 46 | // [ES2015+] Below we used new class declaration, using keyword class 47 | // [ES2015+] We used new constructor method and method declaration 48 | // [ES2015+] We have new pattern implementation with new inheritance 49 | // [ES2015+] Classes are syntactic sugar over JavaScript's prototype-based inheritance 50 | // [ES2015+] We used new keyword const for immutable constant declaration 51 | 52 | class VehiclePrototype { 53 | constructor(model) { 54 | this.model = model; 55 | } 56 | 57 | getModel() { 58 | console.log('The model of this vehicle is..' + this.model); 59 | } 60 | 61 | Clone() {} 62 | } 63 | // [ES2015+] The extends keyword is used to create a class which is a child of another class. 64 | // [ES2015+] A constructor can use the super keyword to call the constructor of the super class. 65 | class Vehicle extends VehiclePrototype { 66 | constructor(model) { 67 | super(model); 68 | } 69 | Clone() { 70 | return new Vehicle(this.model); 71 | } 72 | } 73 | 74 | const car = new Vehicle('Ford Escort'); 75 | const car2 = car.Clone(); 76 | car2.getModel(); 77 | 78 | //********************** Snippet 4 **********************// 79 | // [ES2015+] We used new arrow function syntax 80 | // [ES2015+] We used new keyword const for immutable constant declaration 81 | // [ES2015+] Below we used new class declaration, using keyword class 82 | // [ES2015+] We used new constructor method 83 | // [ES2015+] We still could use Object.prototype for adding new methods, because internally we use the same structure 84 | 85 | const beget = (() => { 86 | class F { 87 | constructor() {} 88 | } 89 | 90 | return proto => { 91 | F.prototype = proto; 92 | return new F(); 93 | }; 94 | })(); 95 | -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/7-the-prototype-pattern.es5.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | 3 | var myCar = { 4 | 5 | name: "Ford Escort", 6 | 7 | drive: function () { 8 | console.log( "Weeee. I'm driving!" ); 9 | }, 10 | 11 | panic: function () { 12 | console.log( "Wait. How do you stop this thing?" ); 13 | } 14 | 15 | }; 16 | 17 | // Use Object.create to instantiate a new car 18 | var yourCar = Object.create( myCar ); 19 | 20 | // Now we can see that one is a prototype of the other 21 | console.log( yourCar.name ); 22 | 23 | //********************** Snippet 2 **********************// 24 | 25 | var vehicle = { 26 | getModel: function () { 27 | console.log( "The model of this vehicle is.." + this.model ); 28 | } 29 | }; 30 | 31 | var car = Object.create(vehicle, { 32 | 33 | "id": { 34 | value: MY_GLOBAL.nextId(), 35 | // writable:false, configurable:false by default 36 | enumerable: true 37 | }, 38 | 39 | "model": { 40 | value: "Ford", 41 | enumerable: true 42 | } 43 | 44 | }); 45 | 46 | //********************** Snippet 3 **********************// 47 | 48 | var vehiclePrototype = { 49 | 50 | init: function ( carModel ) { 51 | this.model = carModel; 52 | }, 53 | 54 | getModel: function () { 55 | console.log( "The model of this vehicle is.." + this.model); 56 | } 57 | }; 58 | 59 | 60 | function vehicle( model ) { 61 | 62 | function F() {}; 63 | F.prototype = vehiclePrototype; 64 | 65 | var f = new F(); 66 | 67 | f.init( model ); 68 | return f; 69 | 70 | } 71 | 72 | var car = vehicle( "Ford Escort" ); 73 | car.getModel(); 74 | 75 | //********************** Snippet 4 **********************// 76 | 77 | var beget = (function () { 78 | 79 | function F() {} 80 | 81 | return function ( proto ) { 82 | F.prototype = proto; 83 | return new F(); 84 | }; 85 | })(); 86 | -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/8-the-command-pattern.es2015.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | // [ES2015+] We used new keyword const for immutable constant declaration 3 | // [ES2015+] We used new template literals for string interpolation 4 | // [ES2015+] We used new arrow function syntax 5 | 6 | (() => { 7 | const carManager = { 8 | // request information 9 | requestInfo(model, id) { 10 | return `The information for ${model} with ID ${id} is foobar`; 11 | }, 12 | 13 | // purchase the car 14 | buyVehicle(model, id) { 15 | return `You have successfully purchased Item ${id}, a ${model}`; 16 | }, 17 | 18 | // arrange a viewing 19 | arrangeViewing(model, id) { 20 | return `You have successfully booked a viewing of ${model} ( ${id} ) `; 21 | }, 22 | }; 23 | })(); 24 | 25 | //********************** Snippet 2 **********************// 26 | 27 | carManager.execute('buyVehicle', 'Ford Escort', '453543'); 28 | 29 | //********************** Snippet 3 **********************// 30 | 31 | carManager.execute = function(name) { 32 | return ( 33 | carManager[name] && 34 | carManager[name].apply(carManager, [].slice.call(arguments, 1)) 35 | ); 36 | }; 37 | 38 | //********************** Snippet 4 **********************// 39 | 40 | carManager.execute('arrangeViewing', 'Ferrari', '14523'); 41 | carManager.execute('requestInfo', 'Ford Mondeo', '54323'); 42 | carManager.execute('requestInfo', 'Ford Escort', '34232'); 43 | carManager.execute('buyVehicle', 'Ford Escort', '34232'); 44 | -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/8-the-command-pattern.es5.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | 3 | (function(){ 4 | 5 | var carManager = { 6 | 7 | // request information 8 | requestInfo: function( model, id ){ 9 | return "The information for " + model + " with ID " + id + " is foobar"; 10 | }, 11 | 12 | // purchase the car 13 | buyVehicle: function( model, id ){ 14 | return "You have successfully purchased Item " + id + ", a " + model; 15 | }, 16 | 17 | // arrange a viewing 18 | arrangeViewing: function( model, id ){ 19 | return "You have successfully booked a viewing of " + model + " ( " + id + " ) "; 20 | } 21 | 22 | }; 23 | 24 | })(); 25 | 26 | //********************** Snippet 2 **********************// 27 | 28 | carManager.execute( "buyVehicle", "Ford Escort", "453543" ); 29 | 30 | //********************** Snippet 3 **********************// 31 | 32 | carManager.execute = function ( name ) { 33 | return carManager[name] && carManager[name].apply( carManager, [].slice.call(arguments, 1) ); 34 | }; 35 | 36 | //********************** Snippet 4 **********************// 37 | 38 | carManager.execute( "arrangeViewing", "Ferrari", "14523" ); 39 | carManager.execute( "requestInfo", "Ford Mondeo", "54323" ); 40 | carManager.execute( "requestInfo", "Ford Escort", "34232" ); 41 | carManager.execute( "buyVehicle", "Ford Escort", "34232" ); -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/9-the-facade-pattern.es2015.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | // [ES2015+] We used new template literals for string interpolation 3 | // [ES2015+] We used new keyword const for immutable constant declaration 4 | // [ES2015+] We used new arrow function syntax 5 | 6 | const addMyEvent = (el, ev, fn) => { 7 | if (el.addEventListener) { 8 | el.addEventListener(ev, fn, false); 9 | } else if (el.attachEvent) { 10 | el.attachEvent(`on${ev}`, fn); 11 | } else { 12 | el[`on${ev}`] = fn; 13 | } 14 | }; 15 | 16 | //********************** Snippet 2 **********************// 17 | 18 | bindReady() { 19 | ... 20 | if (document.addEventListener) { 21 | // Use the handy event callback 22 | document.addEventListener('DOMContentLoaded', DOMContentLoaded, false); 23 | 24 | // A fallback to window.onload, that will always work 25 | window.addEventListener('load', jQuery.ready, false); 26 | 27 | // If IE event model is used 28 | } else if (document.attachEvent) { 29 | 30 | document.attachEvent('onreadystatechange', DOMContentLoaded); 31 | 32 | // A fallback to window.onload, that will always work 33 | window.attachEvent('onload', jQuery.ready); 34 | ... 35 | 36 | 37 | //********************** Snippet 3 **********************// 38 | // [ES2015+] We have new pattern implementation with new keywords import and export 39 | 40 | const _private = { 41 | i: 5, 42 | get() { 43 | console.log(`current value:${this.i}`); 44 | }, 45 | set(val) { 46 | this.i = val; 47 | }, 48 | run() { 49 | console.log('running'); 50 | }, 51 | jump() { 52 | console.log('jumping'); 53 | }, 54 | }; 55 | 56 | // [ES2015+] We used the destructuring assignment syntax that makes it possible to unpack values from data structures into distinct variables. 57 | const module = { 58 | facade({ val, run }) { 59 | _private.set(val); 60 | _private.get(); 61 | if (run) { 62 | _private.run(); 63 | } 64 | }, 65 | }; 66 | // [ES2015+] Default export module, without name 67 | export default module; 68 | 69 | // [ES2015+] The import statement is used to import bindings which are exported by another module. 70 | import module from './module'; 71 | // Outputs: "current value: 10" and "running" 72 | module.facade({ 73 | run: true, 74 | val: 10, 75 | }); 76 | -------------------------------------------------------------------------------- /book/snippets/01-JavaScript-Design-Patterns/9-the-facade-pattern.es5.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | 3 | var addMyEvent = function( el,ev,fn ){ 4 | 5 | if( el.addEventListener ){ 6 | el.addEventListener( ev,fn, false ); 7 | }else if(el.attachEvent){ 8 | el.attachEvent( "on" + ev, fn ); 9 | } else{ 10 | el["on" + ev] = fn; 11 | } 12 | 13 | }; 14 | 15 | 16 | //********************** Snippet 2 **********************// 17 | bindReady: function() { 18 | ... 19 | if ( document.addEventListener ) { 20 | // Use the handy event callback 21 | document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); 22 | 23 | // A fallback to window.onload, that will always work 24 | window.addEventListener( "load", jQuery.ready, false ); 25 | 26 | // If IE event model is used 27 | } else if ( document.attachEvent ) { 28 | 29 | document.attachEvent( "onreadystatechange", DOMContentLoaded ); 30 | 31 | // A fallback to window.onload, that will always work 32 | window.attachEvent( "onload", jQuery.ready ); 33 | ... 34 | 35 | 36 | 37 | //********************** Snippet 3 **********************// 38 | var module = (function() { 39 | 40 | var _private = { 41 | i: 5, 42 | get: function() { 43 | console.log( "current value:" + this.i); 44 | }, 45 | set: function( val ) { 46 | this.i = val; 47 | }, 48 | run: function() { 49 | console.log( "running" ); 50 | }, 51 | jump: function(){ 52 | console.log( "jumping" ); 53 | } 54 | }; 55 | 56 | return { 57 | 58 | facade: function( args ) { 59 | _private.set(args.val); 60 | _private.get(); 61 | if ( args.run ) { 62 | _private.run(); 63 | } 64 | } 65 | }; 66 | }()); 67 | 68 | 69 | // Outputs: "current value: 10" and "running" 70 | module.facade( {run: true, val: 10} ); -------------------------------------------------------------------------------- /book/snippets/02-JavaScript-MV*-Patterns/14-MVC.es2015.js: -------------------------------------------------------------------------------- 1 | //*******************************************************// 2 | // Models 3 | //*******************************************************// 4 | // [ES2015+] We used new keyword const for immutable constant declaration 5 | 6 | //********************** Snippet 1 **********************// 7 | const Photo = Backbone.Model.extend({ 8 | // Default attributes for the photo 9 | defaults: { 10 | src: 'placeholder.jpg', 11 | caption: 'A default image', 12 | viewed: false, 13 | }, 14 | 15 | // Ensure that each photo created has an `src`. 16 | initialize: function() { 17 | this.set({ src: this.defaults.src }); 18 | }, 19 | }); 20 | 21 | //********************** Snippet 2 **********************// 22 | const PhotoGallery = Backbone.Collection.extend({ 23 | // Reference to this collection's model. 24 | model: Photo, 25 | 26 | // Filter down the list of all photos 27 | // that have been viewed 28 | viewed: function() { 29 | return this.filter(function(photo) { 30 | return photo.get('viewed'); 31 | }); 32 | }, 33 | 34 | // Filter down the list to only photos that 35 | // have not yet been viewed 36 | unviewed: function() { 37 | return this.without.apply(this, this.viewed()); 38 | }, 39 | }); 40 | 41 | //*******************************************************// 42 | // Models 43 | //*******************************************************// 44 | 45 | //********************** Snippet 1 **********************// 46 | // [ES2015+] We used new arrow function syntax 47 | 48 | const buildPhotoView = (photoModel, photoController) => { 49 | const base = document.createElement('div'); 50 | const photoEl = document.createElement('div'); 51 | 52 | base.appendChild(photoEl); 53 | 54 | const render = () => { 55 | // We use a templating library such as Underscore 56 | // templating which generates the HTML for our 57 | // photo entry 58 | photoEl.innerHTML = _.template('#photoTemplate', { 59 | src: photoModel.getSrc(), 60 | }); 61 | }; 62 | 63 | photoModel.addSubscriber(render); 64 | 65 | photoEl.addEventListener('click', () => { 66 | photoController.handleEvent('click', photoModel); 67 | }); 68 | 69 | const show = () => { 70 | photoEl.style.display = ''; 71 | }; 72 | 73 | const hide = () => { 74 | photoEl.style.display = 'none'; 75 | }; 76 | 77 | return { 78 | showView: show, 79 | hideView: hide, 80 | }; 81 | }; 82 | 83 | 84 | //********************** Snippet 2 **********************// 85 |
    1. 86 |

      {{caption}}

      87 | 88 | 91 |
    2. 92 | 93 | //********************** Snippet 3 **********************// 94 |
    3. 95 |

      <%= caption %>

      96 | 97 | 100 |
    4. 101 | 102 | //*******************************************************// 103 | // Controllers 104 | //*******************************************************// 105 | 106 | //********************** Snippet 1 **********************// 107 | // Controllers in Spine are created by inheriting from Spine.Controller 108 | 109 | const PhotosController = Spine.Controller.sub({ 110 | init: function() { 111 | this.item.bind('update', this.proxy(this.render)); 112 | this.item.bind('destroy', this.proxy(this.remove)); 113 | }, 114 | 115 | render: function() { 116 | // Handle templating 117 | this.replace($('#photoTemplate').tmpl(this.item)); 118 | return this; 119 | }, 120 | 121 | remove: function() { 122 | this.el.remove(); 123 | this.release(); 124 | }, 125 | }); 126 | 127 | //********************** Snippet 2 **********************// 128 | const PhotoRouter = Backbone.Router.extend({ 129 | routes: { 'photos/:id': 'route' }, 130 | 131 | route: function(id) { 132 | const item = photoCollection.get(id); 133 | const view = new PhotoView({ model: item }); 134 | 135 | $('.content').html(view.render().el); 136 | }, 137 | }); 138 | -------------------------------------------------------------------------------- /book/snippets/02-JavaScript-MV*-Patterns/14-MVC.es5.js: -------------------------------------------------------------------------------- 1 | //*******************************************************// 2 | // Models 3 | //*******************************************************// 4 | 5 | //********************** Snippet 1 **********************// 6 | var Photo = Backbone.Model.extend({ 7 | 8 | // Default attributes for the photo 9 | defaults: { 10 | src: "placeholder.jpg", 11 | caption: "A default image", 12 | viewed: false 13 | }, 14 | 15 | // Ensure that each photo created has an `src`. 16 | initialize: function() { 17 | this.set( { "src": this.defaults.src} ); 18 | } 19 | 20 | }); 21 | 22 | //********************** Snippet 2 **********************// 23 | var PhotoGallery = Backbone.Collection.extend({ 24 | 25 | // Reference to this collection's model. 26 | model: Photo, 27 | 28 | // Filter down the list of all photos 29 | // that have been viewed 30 | viewed: function() { 31 | return this.filter(function( photo ){ 32 | return photo.get( "viewed" ); 33 | }); 34 | }, 35 | 36 | // Filter down the list to only photos that 37 | // have not yet been viewed 38 | unviewed: function() { 39 | return this.without.apply( this, this.viewed() ); 40 | } 41 | }); 42 | 43 | //*******************************************************// 44 | // Models 45 | //*******************************************************// 46 | 47 | //********************** Snippet 1 **********************// 48 | var buildPhotoView = function ( photoModel, photoController ) { 49 | 50 | var base = document.createElement( "div" ), 51 | photoEl = document.createElement( "div" ); 52 | 53 | base.appendChild(photoEl); 54 | 55 | var render = function () { 56 | // We use a templating library such as Underscore 57 | // templating which generates the HTML for our 58 | // photo entry 59 | photoEl.innerHTML = _.template( "#photoTemplate", { 60 | src: photoModel.getSrc() 61 | }); 62 | }; 63 | 64 | photoModel.addSubscriber( render ); 65 | 66 | photoEl.addEventListener( "click", function () { 67 | photoController.handleEvent( "click", photoModel ); 68 | }); 69 | 70 | var show = function () { 71 | photoEl.style.display = ""; 72 | }; 73 | 74 | var hide = function () { 75 | photoEl.style.display = "none"; 76 | }; 77 | 78 | return { 79 | showView: show, 80 | hideView: hide 81 | }; 82 | 83 | }; 84 | 85 | //********************** Snippet 2 **********************// 86 |
    5. 87 |

      {{caption}}

      88 | 89 | 92 |
    6. 93 | 94 | //********************** Snippet 3 **********************// 95 |
    7. 96 |

      <%= caption %>

      97 | 98 | 101 |
    8. 102 | 103 | //*******************************************************// 104 | // Controllers 105 | //*******************************************************// 106 | 107 | //********************** Snippet 1 **********************// 108 | // Controllers in Spine are created by inheriting from Spine.Controller 109 | 110 | var PhotosController = Spine.Controller.sub({ 111 | 112 | init: function () { 113 | this.item.bind( "update", this.proxy( this.render )); 114 | this.item.bind( "destroy", this.proxy( this.remove )); 115 | }, 116 | 117 | render: function () { 118 | // Handle templating 119 | this.replace( $( "#photoTemplate" ).tmpl( this.item ) ); 120 | return this; 121 | }, 122 | 123 | remove: function () { 124 | this.el.remove(); 125 | this.release(); 126 | } 127 | }); 128 | 129 | //********************** Snippet 2 **********************// 130 | var PhotoRouter = Backbone.Router.extend({ 131 | routes: { "photos/:id": "route" }, 132 | 133 | route: function( id ) { 134 | var item = photoCollection.get( id ); 135 | var view = new PhotoView( { model: item } ); 136 | 137 | $('.content').html( view.render().el ); 138 | } 139 | }); 140 | -------------------------------------------------------------------------------- /book/snippets/02-JavaScript-MV*-Patterns/15-MVP.es5-no-changes.js: -------------------------------------------------------------------------------- 1 | //*******************************************************// 2 | // MVC, MVP and Backbone.js 3 | //*******************************************************// 4 | 5 | //********************** Snippet 1 **********************// 6 | var PhotoView = Backbone.View.extend({ 7 | 8 | //... is a list tag. 9 | tagName: "li", 10 | 11 | // Pass the contents of the photo template through a templating 12 | // function, cache it for a single photo 13 | template: _.template( $("#photo-template").html() ), 14 | 15 | // The DOM events specific to an item. 16 | events: { 17 | "click img": "toggleViewed" 18 | }, 19 | 20 | // The PhotoView listens for changes to 21 | // its model, re-rendering. Since there's 22 | // a one-to-one correspondence between a 23 | // **Photo** and a **PhotoView** in this 24 | // app, we set a direct reference on the model for convenience. 25 | 26 | initialize: function() { 27 | this.model.on( "change", this.render, this ); 28 | this.model.on( "destroy", this.remove, this ); 29 | }, 30 | 31 | // Re-render the photo entry 32 | render: function() { 33 | $( this.el ).html( this.template(this.model.toJSON() )); 34 | return this; 35 | }, 36 | 37 | // Toggle the `"viewed"` state of the model. 38 | toggleViewed: function() { 39 | this.model.viewed(); 40 | } 41 | 42 | }); 43 | -------------------------------------------------------------------------------- /book/snippets/02-JavaScript-MV*-Patterns/16-MVVM.es5-no-changes.js: -------------------------------------------------------------------------------- 1 | //*******************************************************// 2 | // Model 3 | //*******************************************************// 4 | 5 | //********************** Snippet 1 **********************// 6 | var Todo = function ( content, done ) { 7 | this.content = ko.observable(content); 8 | this.done = ko.observable(done); 9 | this.editing = ko.observable(false); 10 | }; 11 | 12 | //*******************************************************// 13 | // View 14 | //*******************************************************// 15 | 16 | //********************** Snippet 1 **********************// 17 | var aViewModel = { 18 | contactName: ko.observable("John") 19 | }; 20 | ko.applyBindings(aViewModel); 21 | 22 | //********************** Snippet 2 **********************// 23 |

      24 |
      25 | You have a really long name! 26 |
      27 |

      Contact name:

      28 | 29 | //********************** Snippet 3 **********************// 30 |
      31 |
      32 |

      Todos

      33 | 35 |
      36 |
      37 | 38 | 39 | 40 | 41 |
        42 | 43 | 44 |
      • 45 |
        46 | 47 | 48 | 49 |
        50 | 52 |
      • 53 | 54 |
      55 | 56 |
      57 |
      58 | 59 | 60 | 61 | //*******************************************************// 62 | // ViewModel 63 | //*******************************************************// 64 | 65 | //********************** Snippet 1 **********************// 66 | // our main ViewModel 67 | var ViewModel = function ( todos ) { 68 | var self = this; 69 | 70 | // map array of passed in todos to an observableArray of Todo objects 71 | self.todos = ko.observableArray( 72 | ko.utils.arrayMap( todos, function ( todo ) { 73 | return new Todo( todo.content, todo.done ); 74 | })); 75 | 76 | // store the new todo value being entered 77 | self.current = ko.observable(); 78 | 79 | // add a new todo, when enter key is pressed 80 | self.add = function ( data, event ) { 81 | var newTodo, current = self.current().trim(); 82 | if ( current ) { 83 | newTodo = new Todo( current ); 84 | self.todos.push( newTodo ); 85 | self.current(""); 86 | } 87 | }; 88 | 89 | // remove a single todo 90 | self.remove = function ( todo ) { 91 | self.todos.remove( todo ); 92 | }; 93 | 94 | // remove all completed todos 95 | self.removeCompleted = function () { 96 | self.todos.remove(function (todo) { 97 | return todo.done(); 98 | }); 99 | }; 100 | 101 | // writeable computed observable to handle marking all complete/incomplete 102 | self.allCompleted = ko.computed({ 103 | 104 | // always return true/false based on the done flag of all todos 105 | read:function () { 106 | return !self.remainingCount(); 107 | }, 108 | 109 | // set all todos to the written value (true/false) 110 | write:function ( newValue ) { 111 | ko.utils.arrayForEach( self.todos(), function ( todo ) { 112 | //set even if value is the same, as subscribers are not notified in that case 113 | todo.done( newValue ); 114 | }); 115 | } 116 | }); 117 | 118 | // edit an item 119 | self.editItem = function( item ) { 120 | item.editing( true ); 121 | }; 122 | .. 123 | 124 | //********************** Snippet 2 **********************// 125 | // Define an initially an empty array 126 | var myObservableArray = ko.observableArray(); 127 | 128 | // Add a value to the array and notify our observers 129 | myObservableArray.push( 'A new todo item' ); 130 | -------------------------------------------------------------------------------- /book/snippets/03-Modern-Modular-JavaScript-Design-Patterns/19-CommonJS.es2015.js: -------------------------------------------------------------------------------- 1 | //*******************************************************// 2 | // Getting Started 3 | //*******************************************************// 4 | // [ES2015+] We used new keyword const for immutable constant declaration 5 | // [ES2015+] We used new arrow function syntax 6 | 7 | //********************** Snippet 1 **********************// 8 | // package/lib is a dependency we require 9 | const lib = require('package/lib'); 10 | 11 | // behaviour for our module 12 | const foo = () => { 13 | lib.log('hello world!'); 14 | }; 15 | 16 | // export (expose) foo to other modules 17 | exports.foo = foo; 18 | 19 | //********************** Snippet 2 **********************// 20 | // [ES2015+] Below we used new class declaration, using keyword class 21 | // [ES2015+] We used new constructor method and method declaration 22 | // [ES2015+] Classes are syntactic sugar over JavaScript's prototype-based inheritance 23 | 24 | // define more behaviour we would like to expose 25 | class Foobar { 26 | constructor() { 27 | this.foo = function() { 28 | console.log('Hello foo'); 29 | }; 30 | 31 | this.bar = function() { 32 | console.log('Hello bar'); 33 | }; 34 | } 35 | } 36 | 37 | // expose foobar to other modules 38 | exports.Foobar = Foobar; 39 | 40 | // an application consuming "foobar" 41 | 42 | // access the module relative to the path 43 | // where both usage and module files exist 44 | // in the same directory 45 | 46 | const Foobar = require('./foobar').Foobar; 47 | const test = new Foobar(); 48 | 49 | // Outputs: "Hello bar" 50 | test.bar(); 51 | 52 | //********************** Snippet 3 **********************// 53 | define(function(require) { 54 | var lib = require('package/lib'); 55 | 56 | // some behaviour for our module 57 | function foo() { 58 | lib.log('hello world!'); 59 | } 60 | 61 | // export (expose) foo for other modules 62 | return { 63 | foobar: foo, 64 | }; 65 | }); 66 | 67 | //********************** Snippet 4 **********************// 68 | 69 | const modA = require('./foo'); 70 | const modB = require('./bar'); 71 | 72 | exports.app = () => { 73 | console.log('Im an application!'); 74 | }; 75 | 76 | // [ES2015+] Equivalent to: => { return modA.helloWorld(); } 77 | exports.foo = () => modA.helloWorld(); 78 | 79 | //********************** Snippet 5 **********************// 80 | exports.name = 'bar'; 81 | 82 | //********************** Snippet 6 **********************// 83 | require('./bar'); 84 | // [ES2015+] Equivalent to: => { return "Hello World!!"; } 85 | exports.helloWorld = () => 'Hello World!!'; 86 | -------------------------------------------------------------------------------- /book/snippets/03-Modern-Modular-JavaScript-Design-Patterns/19-CommonJS.es5.js: -------------------------------------------------------------------------------- 1 | //*******************************************************// 2 | // Getting Started 3 | //*******************************************************// 4 | 5 | //********************** Snippet 1 **********************// 6 | // package/lib is a dependency we require 7 | var lib = require( "package/lib" ); 8 | 9 | // behaviour for our module 10 | function foo(){ 11 | lib.log( "hello world!" ); 12 | } 13 | 14 | // export (expose) foo to other modules 15 | exports.foo = foo; 16 | 17 | //********************** Snippet 2 **********************// 18 | // define more behaviour we would like to expose 19 | function foobar(){ 20 | this.foo = function(){ 21 | console.log( "Hello foo" ); 22 | } 23 | 24 | this.bar = function(){ 25 | console.log( "Hello bar" ); 26 | } 27 | } 28 | 29 | // expose foobar to other modules 30 | exports.foobar = foobar; 31 | 32 | // an application consuming "foobar" 33 | 34 | // access the module relative to the path 35 | // where both usage and module files exist 36 | // in the same directory 37 | 38 | var foobar = require("./foobar").foobar, 39 | test = new foobar(); 40 | 41 | // Outputs: "Hello bar" 42 | test.bar(); 43 | 44 | //********************** Snippet 3 **********************// 45 | define(function(require){ 46 | var lib = require( "package/lib" ); 47 | 48 | // some behaviour for our module 49 | function foo(){ 50 | lib.log( "hello world!" ); 51 | } 52 | 53 | // export (expose) foo for other modules 54 | return { 55 | foobar: foo 56 | }; 57 | }); 58 | 59 | //********************** Snippet 4 **********************// 60 | var modA = require( "./foo" ); 61 | var modB = require( "./bar" ); 62 | 63 | exports.app = function(){ 64 | console.log( "Im an application!" ); 65 | } 66 | 67 | exports.foo = function(){ 68 | return modA.helloWorld(); 69 | } 70 | 71 | //********************** Snippet 5 **********************// 72 | exports.name = "bar"; 73 | 74 | //********************** Snippet 6 **********************// 75 | require( "./bar" ); 76 | exports.helloWorld = function(){ 77 | return "Hello World!!" 78 | } 79 | -------------------------------------------------------------------------------- /book/snippets/03-Modern-Modular-JavaScript-Design-Patterns/21-ES-harmony.es5-no-changes.js: -------------------------------------------------------------------------------- 1 | //*******************************************************// 2 | // Modules With Imports And Exports 3 | //*******************************************************// 4 | 5 | //********************** Snippet 1 **********************// 6 | module staff{ 7 | // specify (public) exports that can be consumed by 8 | // other modules 9 | export var baker = { 10 | bake: function( item ){ 11 | console.log( "Woo! I just baked " + item ); 12 | } 13 | } 14 | } 15 | 16 | module skills{ 17 | export var specialty = "baking"; 18 | export var experience = "5 years"; 19 | } 20 | 21 | module cakeFactory{ 22 | 23 | // specify dependencies 24 | import baker from staff; 25 | 26 | // import everything with wildcards 27 | import * from skills; 28 | 29 | export var oven = { 30 | makeCupcake: function( toppings ){ 31 | baker.bake( "cupcake", toppings ); 32 | }, 33 | makeMuffin: function( mSize ){ 34 | baker.bake( "muffin", size ); 35 | } 36 | } 37 | } 38 | 39 | 40 | //*******************************************************// 41 | // Modules Loaded From Remote Sources 42 | //*******************************************************// 43 | 44 | //********************** Snippet 1 **********************// 45 | module cakeFactory from "http://addyosmani.com/factory/cakes.js"; 46 | cakeFactory.oven.makeCupcake( "sprinkles" ); 47 | cakeFactory.oven.makeMuffin( "large" ); 48 | 49 | 50 | //*******************************************************// 51 | // Module Loader API 52 | //*******************************************************// 53 | 54 | //********************** Snippet 1 **********************// 55 | Loader.load( "http://addyosmani.com/factory/cakes.js", 56 | function( cakeFactory ){ 57 | cakeFactory.oven.makeCupcake( "chocolate" ); 58 | }); 59 | 60 | 61 | //*******************************************************// 62 | // CommonJS-like Modules For The Server 63 | //*******************************************************// 64 | 65 | //********************** Snippet 1 **********************// 66 | // io/File.js 67 | export function open( path ) { ... }; 68 | export function close( hnd ) { ... }; 69 | 70 | //********************** Snippet 2 **********************// 71 | // compiler/LexicalHandler.js 72 | module file from "io/File"; 73 | 74 | import { open, close } from file; 75 | export function scan( in ) { 76 | try { 77 | var h = open( in ) ... 78 | } 79 | finally { close( h ) } 80 | } 81 | 82 | //********************** Snippet 3 **********************// 83 | module lexer from "compiler/LexicalHandler"; 84 | module stdlib from "@std"; 85 | 86 | //... scan(cmdline[0]) ... 87 | 88 | 89 | //*******************************************************// 90 | // Classes With Constructors, Getters & Setters 91 | //*******************************************************// 92 | 93 | //********************** Snippet 1 **********************// 94 | class Cake{ 95 | 96 | // We can define the body of a class" constructor 97 | // function by using the keyword "constructor" followed 98 | // by an argument list of public and private declarations. 99 | constructor( name, toppings, price, cakeSize ){ 100 | public name = name; 101 | public cakeSize = cakeSize; 102 | public toppings = toppings; 103 | private price = price; 104 | 105 | } 106 | 107 | // As a part of ES.next's efforts to decrease the unnecessary 108 | // use of "function" for everything, you'll notice that it's 109 | // dropped for cases such as the following. Here an identifier 110 | // followed by an argument list and a body defines a new method 111 | 112 | addTopping( topping ){ 113 | public( this ).toppings.push( topping ); 114 | } 115 | 116 | // Getters can be defined by declaring get before 117 | // an identifier/method name and a curly body. 118 | get allToppings(){ 119 | return public( this ).toppings; 120 | } 121 | 122 | get qualifiesForDiscount(){ 123 | return private( this ).price > 5; 124 | } 125 | 126 | // Similar to getters, setters can be defined by using 127 | // the "set" keyword before an identifier 128 | set cakeSize( cSize ){ 129 | if( cSize < 0 ){ 130 | throw new Error( "Cake must be a valid size - 131 | either small, medium or large" ); 132 | } 133 | public( this ).cakeSize = cSize; 134 | } 135 | 136 | 137 | } 138 | -------------------------------------------------------------------------------- /book/snippets/04-Design-Patterns-In-jQuery/22-the-composite-pattern.es5-no-changes.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | 3 | // Single elements 4 | $( "#singleItem" ).addClass( "active" ); 5 | $( "#container" ).addClass( "active" ); 6 | 7 | // Collections of elements 8 | $( "div" ).addClass( "active" ); 9 | $( ".item" ).addClass( "active" ); 10 | $( "input" ).addClass( "active" ); 11 | 12 | //********************** Snippet 2 **********************// 13 | addClass: function( value ) { 14 | var classNames, i, l, elem, 15 | setClass, c, cl; 16 | 17 | if ( jQuery.isFunction( value ) ) { 18 | return this.each(function( j ) { 19 | jQuery( this ).addClass( value.call(this, j, this.className) ); 20 | }); 21 | } 22 | 23 | if ( value && typeof value === "string" ) { 24 | classNames = value.split( rspace ); 25 | 26 | for ( i = 0, l = this.length; i < l; i++ ) { 27 | elem = this[ i ]; 28 | 29 | if ( elem.nodeType === 1 ) { 30 | if ( !elem.className && classNames.length === 1 ) { 31 | elem.className = value; 32 | 33 | } else { 34 | setClass = " " + elem.className + " "; 35 | 36 | for ( c = 0, cl = classNames.length; c < cl; c++ ) { 37 | if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { 38 | setClass += classNames[ c ] + " "; 39 | } 40 | } 41 | elem.className = jQuery.trim( setClass ); 42 | } 43 | } 44 | } 45 | } 46 | 47 | return this; 48 | } 49 | -------------------------------------------------------------------------------- /book/snippets/04-Design-Patterns-In-jQuery/23-the-adapter-pattern.es5-no-changes.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | // Cross browser opacity: 3 | // opacity: 0.9; Chrome 4+, FF2+, Saf3.1+, Opera 9+, IE9, iOS 3.2+, Android 2.1+ 4 | // filter: alpha(opacity=90); IE6-IE8 5 | 6 | // Setting opacity 7 | $( ".container" ).css( { opacity: .5 } ); 8 | 9 | // Getting opacity 10 | var currentOpacity = $( ".container" ).css('opacity'); 11 | 12 | 13 | //********************** Snippet 2 **********************// 14 | get: function( elem, computed ) { 15 | // IE uses filters for opacity 16 | return ropacity.test( ( 17 | computed && elem.currentStyle ? 18 | elem.currentStyle.filter : elem.style.filter) || "" ) ? 19 | ( parseFloat( RegExp.$1 ) / 100 ) + "" : 20 | computed ? "1" : ""; 21 | }, 22 | 23 | set: function( elem, value ) { 24 | var style = elem.style, 25 | currentStyle = elem.currentStyle, 26 | opacity = jQuery.isNumeric( value ) ? 27 | "alpha(opacity=" + value * 100 + ")" : "", 28 | filter = currentStyle && currentStyle.filter || style.filter || ""; 29 | 30 | // IE has trouble with opacity if it does not have layout 31 | // Force it by setting the zoom level 32 | style.zoom = 1; 33 | 34 | // if setting opacity to 1, and no other filters 35 | //exist - attempt to remove filter attribute #6652 36 | if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) { 37 | 38 | // Setting style.filter to null, "" & " " still leave 39 | // "filter:" in the cssText if "filter:" is present at all, 40 | // clearType is disabled, we want to avoid this style.removeAttribute 41 | // is IE Only, but so apparently is this code path... 42 | style.removeAttribute( "filter" ); 43 | 44 | // if there there is no filter style applied in a css rule, we are done 45 | if ( currentStyle && !currentStyle.filter ) { 46 | return; 47 | } 48 | } 49 | 50 | // otherwise, set new filter values 51 | style.filter = ralpha.test( filter ) ? 52 | filter.replace( ralpha, opacity ) : 53 | filter + " " + opacity; 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /book/snippets/04-Design-Patterns-In-jQuery/24-the-facade-pattern.es5-no-changes.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | $.get( url, data, callback, dataType ); 3 | $.post( url, data, callback, dataType ); 4 | $.getJSON( url, data, callback ); 5 | $.getScript( url, callback ); 6 | 7 | //********************** Snippet 2 **********************// 8 | // $.get() 9 | $.ajax({ 10 | url: url, 11 | data: data, 12 | dataType: dataType 13 | }).done( callback ); 14 | 15 | // $.post 16 | $.ajax({ 17 | type: "POST", 18 | url: url, 19 | data: data, 20 | dataType: dataType 21 | }).done( callback ); 22 | 23 | // $.getJSON() 24 | $.ajax({ 25 | url: url, 26 | dataType: "json", 27 | data: data, 28 | }).done( callback ); 29 | 30 | // $.getScript() 31 | $.ajax({ 32 | url: url, 33 | dataType: "script", 34 | }).done( callback ); 35 | 36 | //********************** Snippet 3 **********************// 37 | // Functions to create xhrs 38 | function createStandardXHR() { 39 | try { 40 | return new window.XMLHttpRequest(); 41 | } catch( e ) {} 42 | } 43 | 44 | function createActiveXHR() { 45 | try { 46 | return new window.ActiveXObject( "Microsoft.XMLHTTP" ); 47 | } catch( e ) {} 48 | } 49 | 50 | // Create the request object 51 | jQuery.ajaxSettings.xhr = window.ActiveXObject ? 52 | /* Microsoft failed to properly 53 | * implement the XMLHttpRequest in IE7 (can't request local files), 54 | * so we use the ActiveXObject when it is available 55 | * Additionally XMLHttpRequest can be disabled in IE7/IE8 so 56 | * we need a fallback. 57 | */ 58 | function() { 59 | return !this.isLocal && createStandardXHR() || createActiveXHR(); 60 | } : 61 | // For all other browsers, use the standard XMLHttpRequest object 62 | createStandardXHR; 63 | ... 64 | 65 | //********************** Snippet 4 **********************// 66 | // Request the remote document 67 | jQuery.ajax({ 68 | url: url, 69 | type: type, 70 | dataType: "html", 71 | data: params, 72 | // Complete callback (responseText is used internally) 73 | complete: function( jqXHR, status, responseText ) { 74 | // Store the response as specified by the jqXHR object 75 | responseText = jqXHR.responseText; 76 | // If successful, inject the HTML into all the matched elements 77 | if ( jqXHR.isResolved() ) { 78 | // Get the actual response in case 79 | // a dataFilter is present in ajaxSettings 80 | jqXHR.done(function( r ) { 81 | responseText = r; 82 | }); 83 | // See if a selector was specified 84 | self.html( selector ? 85 | // Create a dummy div to hold the results 86 | jQuery("
      ") 87 | // inject the contents of the document in, removing the scripts 88 | // to avoid any 'Permission Denied' errors in IE 89 | .append(responseText.replace(rscript, "")) 90 | 91 | // Locate the specified elements 92 | .find(selector) : 93 | 94 | // If not, just inject the full result 95 | responseText ); 96 | } 97 | 98 | if ( callback ) { 99 | self.each( callback, [ responseText, status, jqXHR ] ); 100 | } 101 | } 102 | }); 103 | 104 | return this; 105 | } 106 |
      107 | -------------------------------------------------------------------------------- /book/snippets/04-Design-Patterns-In-jQuery/25-the-observer-pattern.es2015.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | // Equivalent to subscribe(topicName, callback) 3 | $(document).on('topicName', function() { 4 | //..perform some behaviour 5 | }); 6 | 7 | // Equivalent to publish(topicName) 8 | $(document).trigger('topicName'); 9 | 10 | // Equivalent to unsubscribe(topicName) 11 | $(document).off('topicName'); 12 | 13 | //********************** Snippet 2 **********************// 14 | jQuery.event = { 15 | 16 | add: function( elem, types, handler, data, selector ) { 17 | 18 | var elemData, eventHandle, events, 19 | t, tns, type, namespaces, handleObj, 20 | handleObjIn, quick, handlers, special; 21 | 22 | ... 23 | 24 | // Init the element's event structure and main handler, 25 | //if this is the first 26 | events = elemData.events; 27 | if ( !events ) { 28 | elemData.events = events = {}; 29 | } 30 | ... 31 | 32 | // Handle multiple events separated by a space 33 | // jQuery(...).bind("mouseover mouseout", fn); 34 | types = jQuery.trim( hoverHack(types) ).split( " " ); 35 | for ( t = 0; t < types.length; t++ ) { 36 | 37 | ... 38 | 39 | // Init the event handler queue if we're the first 40 | handlers = events[ type ]; 41 | if ( !handlers ) { 42 | handlers = events[ type ] = []; 43 | handlers.delegateCount = 0; 44 | 45 | // Only use addEventListener/attachEvent if the special 46 | // events handler returns false 47 | if ( !special.setup || special.setup.call( elem, data, 48 | //namespaces, eventHandle ) === false ) { 49 | // Bind the global event handler to the element 50 | if ( elem.addEventListener ) { 51 | elem.addEventListener( type, eventHandle, false ); 52 | 53 | } else if ( elem.attachEvent ) { 54 | elem.attachEvent( "on" + type, eventHandle ); 55 | } 56 | } 57 | } 58 | 59 | //********************** Snippet 3 **********************// 60 | // [ES2015+] We used new keyword const for immutable constant declaration 61 | // [SE2015+] We used new keyword let, which declares a block scope local variable 62 | // [ES2015+] We used new arrow function syntax 63 | 64 | const topics = {}; 65 | 66 | jQuery.Topic = id => { 67 | let callbacks; 68 | let topic = id && topics[id]; 69 | if (!topic) { 70 | callbacks = jQuery.Callbacks(); 71 | topic = { 72 | publish: callbacks.fire, 73 | subscribe: callbacks.add, 74 | unsubscribe: callbacks.remove, 75 | }; 76 | if (id) { 77 | topics[id] = topic; 78 | } 79 | } 80 | return topic; 81 | }; 82 | 83 | //********************** Snippet 4 **********************// 84 | // Subscribers 85 | $.Topic('mailArrived').subscribe(fn1); 86 | $.Topic('mailArrived').subscribe(fn2); 87 | $.Topic('mailSent').subscribe(fn1); 88 | 89 | // Publisher 90 | $.Topic('mailArrived').publish('hello world!'); 91 | $.Topic('mailSent').publish('woo! mail!'); 92 | 93 | // Here, "hello world!" gets pushed to fn1 and fn2 94 | // when the "mailArrived" notification is published 95 | // with "woo! mail!" also being pushed to fn1 when 96 | // the "mailSent" notification is published. 97 | 98 | // Outputs: 99 | // hello world! 100 | // fn2 says: hello world! 101 | // woo! mail! 102 | -------------------------------------------------------------------------------- /book/snippets/04-Design-Patterns-In-jQuery/25-the-observer-pattern.es5.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | // Equivalent to subscribe(topicName, callback) 3 | $( document ).on( "topicName", function () { 4 | //..perform some behaviour 5 | }); 6 | 7 | // Equivalent to publish(topicName) 8 | $( document ).trigger( "topicName" ); 9 | 10 | // Equivalent to unsubscribe(topicName) 11 | $( document ).off( "topicName" ); 12 | 13 | //********************** Snippet 2 **********************// 14 | jQuery.event = { 15 | 16 | add: function( elem, types, handler, data, selector ) { 17 | 18 | var elemData, eventHandle, events, 19 | t, tns, type, namespaces, handleObj, 20 | handleObjIn, quick, handlers, special; 21 | 22 | ... 23 | 24 | // Init the element's event structure and main handler, 25 | //if this is the first 26 | events = elemData.events; 27 | if ( !events ) { 28 | elemData.events = events = {}; 29 | } 30 | ... 31 | 32 | // Handle multiple events separated by a space 33 | // jQuery(...).bind("mouseover mouseout", fn); 34 | types = jQuery.trim( hoverHack(types) ).split( " " ); 35 | for ( t = 0; t < types.length; t++ ) { 36 | 37 | ... 38 | 39 | // Init the event handler queue if we're the first 40 | handlers = events[ type ]; 41 | if ( !handlers ) { 42 | handlers = events[ type ] = []; 43 | handlers.delegateCount = 0; 44 | 45 | // Only use addEventListener/attachEvent if the special 46 | // events handler returns false 47 | if ( !special.setup || special.setup.call( elem, data, 48 | //namespaces, eventHandle ) === false ) { 49 | // Bind the global event handler to the element 50 | if ( elem.addEventListener ) { 51 | elem.addEventListener( type, eventHandle, false ); 52 | 53 | } else if ( elem.attachEvent ) { 54 | elem.attachEvent( "on" + type, eventHandle ); 55 | } 56 | } 57 | } 58 | 59 | //********************** Snippet 3 **********************// 60 | var topics = {}; 61 | 62 | jQuery.Topic = function( id ) { 63 | var callbacks, 64 | topic = id && topics[ id ]; 65 | if ( !topic ) { 66 | callbacks = jQuery.Callbacks(); 67 | topic = { 68 | publish: callbacks.fire, 69 | subscribe: callbacks.add, 70 | unsubscribe: callbacks.remove 71 | }; 72 | if ( id ) { 73 | topics[ id ] = topic; 74 | } 75 | } 76 | return topic; 77 | }; 78 | 79 | //********************** Snippet 4 **********************// 80 | // Subscribers 81 | $.Topic( "mailArrived" ).subscribe( fn1 ); 82 | $.Topic( "mailArrived" ).subscribe( fn2 ); 83 | $.Topic( "mailSent" ).subscribe( fn1 ); 84 | 85 | // Publisher 86 | $.Topic( "mailArrived" ).publish( "hello world!" ); 87 | $.Topic( "mailSent" ).publish( "woo! mail!" ); 88 | 89 | // Here, "hello world!" gets pushed to fn1 and fn2 90 | // when the "mailArrived" notification is published 91 | // with "woo! mail!" also being pushed to fn1 when 92 | // the "mailSent" notification is published. 93 | 94 | // Outputs: 95 | // hello world! 96 | // fn2 says: hello world! 97 | // woo! mail! 98 | -------------------------------------------------------------------------------- /book/snippets/04-Design-Patterns-In-jQuery/26-the-iterator-pattern.es2015.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | // [ES2015+] We used new template literals for string interpolation 3 | // [ES2015+] We used new arrow function syntax 4 | 5 | $.each(['john', 'dave', 'rick', 'julian'], (index, value) => { 6 | console.log(`${index}: ${value}`); 7 | }); 8 | 9 | $('li').each(function(index) { 10 | console.log(`${index}: ${$(this).text()}`); 11 | }); 12 | 13 | //********************** Snippet 2 **********************// 14 | // Execute a callback for every element in the matched set. 15 | each: function( callback, args ) { 16 | return jQuery.each( this, callback, args ); 17 | } 18 | 19 | //********************** Snippet 3 **********************// 20 | each: function( object, callback, args ) { 21 | var name, i = 0, 22 | length = object.length, 23 | isObj = length === undefined || jQuery.isFunction( object ); 24 | 25 | if ( args ) { 26 | if ( isObj ) { 27 | for ( name in object ) { 28 | if ( callback.apply( object[ name ], args ) === false ) { 29 | break; 30 | } 31 | } 32 | } else { 33 | for ( ; i < length; ) { 34 | if ( callback.apply( object[ i++ ], args ) === false ) { 35 | break; 36 | } 37 | } 38 | } 39 | 40 | // A special, fast, case for the most common use of each 41 | } else { 42 | if ( isObj ) { 43 | for ( name in object ) { 44 | if ( callback.call( object[ name ], name, object[ name ] ) === false ) { 45 | break; 46 | } 47 | } 48 | } else { 49 | for ( ; i < length; ) { 50 | if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { 51 | break; 52 | } 53 | } 54 | } 55 | } 56 | 57 | return object; 58 | }; 59 | -------------------------------------------------------------------------------- /book/snippets/04-Design-Patterns-In-jQuery/26-the-iterator-pattern.es5.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | $.each( ["john","dave","rick","julian"], function( index, value ) { 3 | console.log( index + ": " + value); 4 | }); 5 | 6 | $( "li" ).each( function ( index ) { 7 | console.log( index + ": " + $( this ).text()); 8 | }); 9 | 10 | //********************** Snippet 2 **********************// 11 | // Execute a callback for every element in the matched set. 12 | each: function( callback, args ) { 13 | return jQuery.each( this, callback, args ); 14 | } 15 | 16 | //********************** Snippet 3 **********************// 17 | each: function( object, callback, args ) { 18 | var name, i = 0, 19 | length = object.length, 20 | isObj = length === undefined || jQuery.isFunction( object ); 21 | 22 | if ( args ) { 23 | if ( isObj ) { 24 | for ( name in object ) { 25 | if ( callback.apply( object[ name ], args ) === false ) { 26 | break; 27 | } 28 | } 29 | } else { 30 | for ( ; i < length; ) { 31 | if ( callback.apply( object[ i++ ], args ) === false ) { 32 | break; 33 | } 34 | } 35 | } 36 | 37 | // A special, fast, case for the most common use of each 38 | } else { 39 | if ( isObj ) { 40 | for ( name in object ) { 41 | if ( callback.call( object[ name ], name, object[ name ] ) === false ) { 42 | break; 43 | } 44 | } 45 | } else { 46 | for ( ; i < length; ) { 47 | if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { 48 | break; 49 | } 50 | } 51 | } 52 | } 53 | 54 | return object; 55 | }; 56 | -------------------------------------------------------------------------------- /book/snippets/04-Design-Patterns-In-jQuery/27-the-lazy-initialization-pattern.es2015.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | // [ES2015+] We used new template literals for string interpolation 3 | // [ES2015+] We used new keyword const for immutable constant declaration 4 | // [ES2015+] We used new arrow function syntax 5 | 6 | $(document).ready(() => { 7 | // The ajax request won't attempt to execute until 8 | // the DOM is ready 9 | 10 | const jqxhr = $.ajax({ 11 | url: 'http://domain.com/api/', 12 | data: 'display=latest&order=ascending', 13 | }).done((data) => { 14 | $('.status').html('content loaded'); 15 | console.log(`Data output:${data}`); 16 | }); 17 | }); 18 | 19 | 20 | //********************** Snippet 2 **********************// 21 | bindReady: function() { 22 | if ( readyList ) { 23 | return; 24 | } 25 | 26 | readyList = jQuery.Callbacks( "once memory" ); 27 | 28 | // Catch cases where $(document).ready() is called after the 29 | // browser event has already occurred. 30 | if ( document.readyState === "complete" ) { 31 | // Handle it asynchronously to allow scripts the opportunity to delay ready 32 | return setTimeout( jQuery.ready, 1 ); 33 | } 34 | 35 | // Mozilla, Opera and webkit support this event 36 | if ( document.addEventListener ) { 37 | // Use the handy event callback 38 | document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); 39 | 40 | // A fallback to window.onload, that will always work 41 | window.addEventListener( "load", jQuery.ready, false ); 42 | 43 | // If IE event model is used 44 | } else if ( document.attachEvent ) { 45 | // ensure firing before onload, 46 | // maybe late but safe also for iframes 47 | document.attachEvent( "onreadystatechange", DOMContentLoaded ); 48 | 49 | // A fallback to window.onload, that will always work 50 | window.attachEvent( "onload", jQuery.ready ); 51 | 52 | // If IE and not a frame 53 | // continually check to see if the document is ready 54 | var toplevel = false; 55 | 56 | try { 57 | toplevel = window.frameElement == null; 58 | } catch(e) {} 59 | 60 | if ( document.documentElement.doScroll && toplevel ) { 61 | doScrollCheck(); 62 | } 63 | } 64 | }, 65 | -------------------------------------------------------------------------------- /book/snippets/04-Design-Patterns-In-jQuery/27-the-lazy-initialization-pattern.es5.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | $( document ).ready( function () { 3 | 4 | // The ajax request won't attempt to execute until 5 | // the DOM is ready 6 | 7 | var jqxhr = $.ajax({ 8 | url: "http://domain.com/api/", 9 | data: "display=latest&order=ascending" 10 | }) 11 | .done( function( data ) ){ 12 | $(".status").html( "content loaded" ); 13 | console.log( "Data output:" + data ); 14 | }); 15 | 16 | }); 17 | 18 | //********************** Snippet 2 **********************// 19 | bindReady: function() { 20 | if ( readyList ) { 21 | return; 22 | } 23 | 24 | readyList = jQuery.Callbacks( "once memory" ); 25 | 26 | // Catch cases where $(document).ready() is called after the 27 | // browser event has already occurred. 28 | if ( document.readyState === "complete" ) { 29 | // Handle it asynchronously to allow scripts the opportunity to delay ready 30 | return setTimeout( jQuery.ready, 1 ); 31 | } 32 | 33 | // Mozilla, Opera and webkit support this event 34 | if ( document.addEventListener ) { 35 | // Use the handy event callback 36 | document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); 37 | 38 | // A fallback to window.onload, that will always work 39 | window.addEventListener( "load", jQuery.ready, false ); 40 | 41 | // If IE event model is used 42 | } else if ( document.attachEvent ) { 43 | // ensure firing before onload, 44 | // maybe late but safe also for iframes 45 | document.attachEvent( "onreadystatechange", DOMContentLoaded ); 46 | 47 | // A fallback to window.onload, that will always work 48 | window.attachEvent( "onload", jQuery.ready ); 49 | 50 | // If IE and not a frame 51 | // continually check to see if the document is ready 52 | var toplevel = false; 53 | 54 | try { 55 | toplevel = window.frameElement == null; 56 | } catch(e) {} 57 | 58 | if ( document.documentElement.doScroll && toplevel ) { 59 | doScrollCheck(); 60 | } 61 | } 62 | }, 63 | -------------------------------------------------------------------------------- /book/snippets/04-Design-Patterns-In-jQuery/28-the-proxy-pattern.es5-no-changes.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | $( "button" ).on( "click", function () { 3 | // Within this function, "this" refers to the element that was clicked 4 | $( this ).addClass( "active" ); 5 | }); 6 | 7 | //********************** Snippet 2 **********************// 8 | $( "button" ).on( "click", function () { 9 | setTimeout(function () { 10 | // "this" doesn't refer to our element! 11 | // It refers to window 12 | $( this ).addClass( "active" ); 13 | }); 14 | }); 15 | 16 | //********************** Snippet 3 **********************// 17 | $( "button" ).on( "click", function () { 18 | 19 | setTimeout( $.proxy( function () { 20 | // "this" now refers to our element as we wanted 21 | $( this ).addClass( "active" ); 22 | }, this), 500); 23 | 24 | // the last "this" we're passing tells $.proxy() that our DOM element 25 | // is the value we want "this" to refer to. 26 | }); 27 | 28 | //********************** Snippet 4 **********************// 29 | // Bind a function to a context, optionally partially applying any 30 | // arguments. 31 | proxy: function( fn, context ) { 32 | if ( typeof context === "string" ) { 33 | var tmp = fn[ context ]; 34 | context = fn; 35 | fn = tmp; 36 | } 37 | 38 | // Quick check to determine if target is callable, in the spec 39 | // this throws a TypeError, but we will just return undefined. 40 | if ( !jQuery.isFunction( fn ) ) { 41 | return undefined; 42 | } 43 | 44 | // Simulated bind 45 | var args = slice.call( arguments, 2 ), 46 | proxy = function() { 47 | return fn.apply( context, args.concat( slice.call( arguments ) ) ); 48 | }; 49 | 50 | // Set the guid of unique handler to the same of original handler, so it can be removed 51 | proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; 52 | 53 | return proxy; 54 | } 55 | -------------------------------------------------------------------------------- /book/snippets/04-Design-Patterns-In-jQuery/29-the-builder-pattern.es2015.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | // [ES2015+] We used new keyword const for immutable constant declaration 3 | $('
      bar
      '); 4 | 5 | $('

      foo bar

      ').appendTo('body'); 6 | 7 | const newParagraph = $('

      ').text('Hello world'); 8 | 9 | $('') 10 | .attr({ type: 'text', id: 'sample' }) 11 | .appendTo('#container'); 12 | 13 | //********************** Snippet 1 **********************// 14 | 15 | // HANDLE: $(html) -> $(array) 16 | if ( match[1] ) { 17 | context = context instanceof jQuery ? context[0] : context; 18 | doc = ( context ? context.ownerDocument || context : document ); 19 | 20 | // If a single string is passed in and it's a single tag 21 | // just do a createElement and skip the rest 22 | ret = rsingleTag.exec( selector ); 23 | 24 | if ( ret ) { 25 | if ( jQuery.isPlainObject( context ) ) { 26 | selector = [ document.createElement( ret[1] ) ]; 27 | jQuery.fn.attr.call( selector, context, true ); 28 | 29 | } else { 30 | selector = [ doc.createElement( ret[1] ) ]; 31 | } 32 | 33 | } else { 34 | ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); 35 | selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; 36 | } 37 | 38 | return jQuery.merge( this, selector ); 39 | -------------------------------------------------------------------------------- /book/snippets/04-Design-Patterns-In-jQuery/29-the-builder-pattern.es5.js: -------------------------------------------------------------------------------- 1 | //********************** Snippet 1 **********************// 2 | $( '

      bar
      ' ); 3 | 4 | $( '

      foo bar

      ').appendTo("body"); 5 | 6 | var newParagraph = $( "

      " ).text( "Hello world" ); 7 | 8 | $( "" ) 9 | .attr({ "type": "text", "id":"sample"}) 10 | .appendTo("#container"); 11 | 12 | //********************** Snippet 1 **********************// 13 | 14 | // HANDLE: $(html) -> $(array) 15 | if ( match[1] ) { 16 | context = context instanceof jQuery ? context[0] : context; 17 | doc = ( context ? context.ownerDocument || context : document ); 18 | 19 | // If a single string is passed in and it's a single tag 20 | // just do a createElement and skip the rest 21 | ret = rsingleTag.exec( selector ); 22 | 23 | if ( ret ) { 24 | if ( jQuery.isPlainObject( context ) ) { 25 | selector = [ document.createElement( ret[1] ) ]; 26 | jQuery.fn.attr.call( selector, context, true ); 27 | 28 | } else { 29 | selector = [ doc.createElement( ret[1] ) ]; 30 | } 31 | 32 | } else { 33 | ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); 34 | selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; 35 | } 36 | 37 | return jQuery.merge( this, selector ); 38 | -------------------------------------------------------------------------------- /book/styles/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #fafafa; 3 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 4 | color: #333; 5 | } 6 | 7 | .hero-unit { 8 | margin: 50px auto 0 auto; 9 | width: 300px; 10 | font-size: 18px; 11 | font-weight: 200; 12 | line-height: 30px; 13 | background-color: #eee; 14 | border-radius: 6px; 15 | padding: 60px; 16 | } 17 | 18 | .hero-unit h1 { 19 | font-size: 60px; 20 | line-height: 1; 21 | letter-spacing: -1px; 22 | } 23 | 24 | .browsehappy { 25 | margin: 0.2em 0; 26 | background: #ccc; 27 | color: #000; 28 | padding: 0.2em 0; 29 | } 30 | -------------------------------------------------------------------------------- /book/styles/print.css: -------------------------------------------------------------------------------- 1 | /* print.css */ 2 | body { 3 | line-height:1.5; 4 | font-family: Palatino, "Palatino LT Std", "Palatino Linotype", Georgia, Times, "Times New Roman", serif; 5 | color:#000; 6 | background:none; 7 | font-size:10pt; 8 | } 9 | .container {background:none;} 10 | hr {background:#ccc;color:#ccc;width:100%;height:2px;margin:2em 0;padding:0;border:none;} 11 | hr.space {background:#fff;color:#fff;visibility:hidden;} 12 | h1, h2, h3, h4, h5, h6 { 13 | font-family: Palatino, "Palatino LT Std", "Palatino Linotype", Georgia, Times, "Times New Roman", serif; 14 | } 15 | code {font:.9em "Courier New", Monaco, Courier, monospace;} 16 | a img {border:none;} 17 | p img.top {margin-top:0;} 18 | blockquote {margin:1.5em;padding:1em;font-style:italic;font-size:.9em;} 19 | .hide {display:none;} 20 | a:link, a:visited {background:transparent;font-weight:700;text-decoration:underline;} 21 | a:link:after, a:visited:after {content:" (" attr(href) ")";font-size:90%;} -------------------------------------------------------------------------------- /book/styles/sausage.css: -------------------------------------------------------------------------------- 1 | .sausage-set { 2 | position: fixed; right: 0; top: 0; 3 | width: 15px; height: 100%; 4 | border-left: solid 2px #fff; 5 | border-right: solid 2px #fff; 6 | background-color: #fff; 7 | font-family: 'Helvetica Neue', 'Arial', 'sans-serif'; 8 | } 9 | .sausage { 10 | position: absolute; left: 0; 11 | width: 100%; height: 100%; 12 | background-color: #f1f1f1; 13 | text-decoration: none; 14 | -moz-border-radius: 8px; 15 | -webkit-border-bottom-left-radius: 8px; 16 | -webkit-border-top-left-radius: 8px; 17 | -webkit-border-bottom-right-radius: 8px; 18 | -webkit-border-top-right-radius: 8px; 19 | -moz-box-shadow: inset 0px 1px 2px 4px rgba(0, 0, 0, 0.025); 20 | -webkit-box-shadow: inset 0px 1px 2px 4px rgba(0, 0, 0, 0.025); 21 | cursor: pointer; 22 | } 23 | .sausage-hover, 24 | .sausage-current { 25 | background-color: #f2e4ed; 26 | -moz-box-shadow: inset 0px 1px 2px 4px rgba(51, 63, 70, 0.025); 27 | } 28 | .sausage-span { 29 | position: absolute; right: 24px; top: 5px; z-index: 2; 30 | display: none; 31 | width: 100px; 32 | padding: 2px 3px; 33 | color: #000; 34 | background-color: #fff; 35 | border: solid 2px #990066; 36 | font-size: 10px; line-height: 12px; font-weight: bold; text-align: center; 37 | -moz-border-radius: 7px; 38 | -webkit-border-bottom-left-radius: 7px; 39 | -webkit-border-top-left-radius: 7px; 40 | -webkit-border-bottom-right-radius: 7px; 41 | -webkit-border-top-right-radius: 7px; 42 | -moz-box-shadow: 1px 1px 1px 1px rgba(0, 0, 0, 0.05); 43 | -webkit-box-shadow: 1px 1px 1px 1px rgba(0, 0, 0, 0.05); 44 | } 45 | .sausage-hover .sausage-span, 46 | .sausage-current .sausage-span { 47 | display: block; 48 | } -------------------------------------------------------------------------------- /book/styles/shThemeRDark.css: -------------------------------------------------------------------------------- 1 | .syntaxhighlighter{background-color:#1b2426 !important;} 2 | .syntaxhighlighter .line.alt1{background-color:#1b2426 !important;} 3 | .syntaxhighlighter .line.alt2{background-color:#1b2426 !important;} 4 | .syntaxhighlighter .line.highlighted.alt1,.syntaxhighlighter .line.highlighted.alt2{background-color:#323e41 !important;} 5 | .syntaxhighlighter .line.highlighted.number{color:#b9bdb6 !important;} 6 | .syntaxhighlighter table caption{color:#b9bdb6 !important;} 7 | .syntaxhighlighter .gutter{color:#afafaf !important;} 8 | .syntaxhighlighter .gutter .line{border-right:3px solid #435a5f !important;} 9 | .syntaxhighlighter .gutter .line.highlighted{background-color:#435a5f !important;color:#1b2426 !important;} 10 | .syntaxhighlighter.printing .line .content{border:none !important;} 11 | .syntaxhighlighter.collapsed{overflow:visible !important;} 12 | .syntaxhighlighter.collapsed .toolbar{color:#5ba1cf !important;background:black !important;border:1px solid #435a5f !important;} 13 | .syntaxhighlighter.collapsed .toolbar a{color:#5ba1cf !important;} 14 | .syntaxhighlighter.collapsed .toolbar a:hover{color:#5ce638 !important;} 15 | .syntaxhighlighter .toolbar{color:white !important;background:#435a5f !important;border:none !important;} 16 | .syntaxhighlighter .toolbar a{color:white !important;} 17 | .syntaxhighlighter .toolbar a:hover{color:#e0e8ff !important;} 18 | .syntaxhighlighter .plain,.syntaxhighlighter .plain a{color:#b9bdb6 !important;} 19 | .syntaxhighlighter .comments,.syntaxhighlighter .comments a{color:#878a85 !important;} 20 | .syntaxhighlighter .string,.syntaxhighlighter .string a{color:#5ce638 !important;} 21 | .syntaxhighlighter .keyword{color:#5ba1cf !important;} 22 | .syntaxhighlighter .preprocessor{color:#435a5f !important;} 23 | .syntaxhighlighter .variable{color:#ffaa3e !important;} 24 | .syntaxhighlighter .value{color:#009900 !important;} 25 | .syntaxhighlighter .functions{color:#ffaa3e !important;} 26 | .syntaxhighlighter .constants{color:#e0e8ff !important;} 27 | .syntaxhighlighter .script{font-weight:bold !important;color:#5ba1cf !important;background-color:none !important;} 28 | .syntaxhighlighter .color1,.syntaxhighlighter .color1 a{color:#e0e8ff !important;} 29 | .syntaxhighlighter .color2,.syntaxhighlighter .color2 a{color:white !important;} 30 | .syntaxhighlighter .color3,.syntaxhighlighter .color3 a{color:#ffaa3e !important;} 31 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsdp", 3 | "private": true, 4 | "dependencies": { 5 | "jquery": "~1.10.2", 6 | "codecode": "~0.1.2" 7 | }, 8 | "devDependencies": {} 9 | } 10 | -------------------------------------------------------------------------------- /cover/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/cover/cover.jpg -------------------------------------------------------------------------------- /diagrams/command.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/command.png -------------------------------------------------------------------------------- /diagrams/constructor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/constructor.png -------------------------------------------------------------------------------- /diagrams/facade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/facade.png -------------------------------------------------------------------------------- /diagrams/factory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/factory.png -------------------------------------------------------------------------------- /diagrams/flyweight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/flyweight.png -------------------------------------------------------------------------------- /diagrams/mediator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/mediator.png -------------------------------------------------------------------------------- /diagrams/mixins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/mixins.png -------------------------------------------------------------------------------- /diagrams/module.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/module.png -------------------------------------------------------------------------------- /diagrams/mvc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/mvc.png -------------------------------------------------------------------------------- /diagrams/mvp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/mvp.png -------------------------------------------------------------------------------- /diagrams/mvvm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/mvvm.png -------------------------------------------------------------------------------- /diagrams/observer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/observer.png -------------------------------------------------------------------------------- /diagrams/prototype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/prototype.png -------------------------------------------------------------------------------- /diagrams/publishsubscribe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/publishsubscribe.png -------------------------------------------------------------------------------- /diagrams/singleton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/diagrams/singleton.png -------------------------------------------------------------------------------- /extras/designpatterns-printable-referencecards/design-patterns-printable.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/extras/designpatterns-printable-referencecards/design-patterns-printable.pdf -------------------------------------------------------------------------------- /extras/dzone-designpatterns-cheatsheet/rc008-designpatterns_online.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/extras/dzone-designpatterns-cheatsheet/rc008-designpatterns_online.pdf -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "essential-js-design-patterns", 3 | "version": "1.7.0", 4 | "description": "A book on JavaScript Design Patterns", 5 | "main": "book/index.html", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/addyosmani/essential-js-design-patterns" 9 | }, 10 | "keywords": [ 11 | "javascript", 12 | "patterns", 13 | "book" 14 | ], 15 | "author": "Addy Osmani", 16 | "license": "Creative Commons Attribution-No Derivative Works", 17 | "bugs": { 18 | "url": "https://github.com/addyosmani/essential-js-design-patterns/issues" 19 | }, 20 | "homepage": "https://github.com/addyosmani/essential-js-design-patterns", 21 | "devDependencies": { 22 | "grunt": "^0.4.5", 23 | "grunt-autoprefixer": "^2.0.0", 24 | "grunt-bower-install": "~1.6.0", 25 | "grunt-concurrent": "^1.0.0", 26 | "grunt-contrib-clean": "~0.6.0", 27 | "grunt-contrib-compass": "^1.0.1", 28 | "grunt-contrib-concat": "~0.5.0", 29 | "grunt-contrib-connect": "^0.9.0", 30 | "grunt-contrib-copy": "^0.7.0", 31 | "grunt-contrib-cssmin": "^0.11.0", 32 | "grunt-contrib-htmlmin": "~0.3.0", 33 | "grunt-contrib-imagemin": "^2.0.0", 34 | "grunt-contrib-jshint": "~0.10.0", 35 | "grunt-contrib-uglify": "^0.7.0", 36 | "grunt-contrib-watch": "~0.6.1", 37 | "grunt-mocha": "~0.4.0", 38 | "grunt-newer": "^0.8.0", 39 | "grunt-rev": "~0.1.0", 40 | "grunt-svgmin": "^2.0.0", 41 | "grunt-usemin": "^3.0.0", 42 | "jshint-stylish": "^1.0.0", 43 | "load-grunt-tasks": "^2.0.0", 44 | "time-grunt": "~1.0.0" 45 | }, 46 | "engines": { 47 | "node": ">=0.8.0" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /test/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsdp", 3 | "private": true, 4 | "dependencies": { 5 | "chai": "~1.8.0", 6 | "mocha": "~1.14.0" 7 | }, 8 | "devDependencies": {} 9 | } 10 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Mocha Spec Runner 7 | 8 | 9 | 10 |

      11 | 12 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/spec/test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | (function () { 4 | 'use strict'; 5 | 6 | describe('Give it some context', function () { 7 | describe('maybe a bit more context here', function () { 8 | it('should run here few assertions', function () { 9 | 10 | }); 11 | }); 12 | }); 13 | })(); 14 | --------------------------------------------------------------------------------