├── .gitignore ├── CHANGELOG.md ├── Gemfile ├── Gemfile.lock ├── MIT-LICENSE ├── README.md ├── Rakefile ├── app └── helpers │ └── requirejs_helper.rb ├── bin └── r.js ├── lib ├── requirejs-rails.rb ├── requirejs │ ├── error.rb │ ├── rails.rb │ └── rails │ │ ├── builder.rb │ │ ├── config.rb │ │ ├── engine.rb │ │ ├── rjs_driver.js.erb │ │ ├── version.rb │ │ └── view.rb └── tasks │ └── requirejs-rails_tasks.rake ├── requirejs-rails.gemspec ├── test ├── dummy │ ├── .rvmrc │ ├── Rakefile │ ├── app │ │ ├── assets │ │ │ ├── javascripts │ │ │ │ └── application.js │ │ │ └── stylesheets │ │ │ │ └── application.css │ │ ├── controllers │ │ │ └── application_controller.rb │ │ ├── helpers │ │ │ └── application_helper.rb │ │ ├── mailers │ │ │ └── .gitkeep │ │ ├── models │ │ │ └── .gitkeep │ │ └── views │ │ │ └── layouts │ │ │ └── application.html.erb │ ├── config.ru │ ├── config │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── database.yml │ │ ├── environment.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers │ │ │ ├── backtrace_silencers.rb │ │ │ ├── inflections.rb │ │ │ ├── mime_types.rb │ │ │ ├── secret_token.rb │ │ │ ├── session_store.rb │ │ │ └── wrap_parameters.rb │ │ ├── locales │ │ │ └── en.yml │ │ └── routes.rb │ ├── db │ │ └── .gitkeep │ ├── lib │ │ └── assets │ │ │ └── .gitkeep │ ├── log │ │ └── .gitkeep │ ├── public │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ └── favicon.ico │ └── script │ │ └── rails ├── requirejs-rails_test.rb └── test_helper.rb └── vendor └── assets └── javascripts ├── almond.js └── require.js /.gitignore: -------------------------------------------------------------------------------- 1 | /.ruby-version 2 | /.bundle/ 3 | /log/*.log 4 | /pkg/ 5 | /test/dummy/db/*.sqlite3 6 | /test/dummy/log/*.log 7 | /test/dummy/tmp/ 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## requirejs-rails changelog 4 | 5 | ### v1.0.1 6 | 7 | 8 | - Update `require.js` and `r.js` to `2.3.5`, and `almond.js` to `0.3.3`. 9 | - Add `wrapShim` to `build_config_whitelist`. 10 | 11 | ### v1.0.0 12 | 13 | - Update `require.js` and `r.js` to `2.1.22`. 14 | - Fix a `sass-rails` `3.*.*` backwards compatibility issue (credit `@merqlove`). 15 | - Fix a Sprockets `3.3.0` backwards compatibility issue (credit `@swils`). 16 | 17 | ### v0.9.9 18 | 19 | - Fix an asset digesting regression in #238 (credit @jonhyman). 20 | - Update `require.js` and `r.js` to `2.1.19`. 21 | 22 | ### v0.9.8 23 | 24 | - Fix a bad regression and yank v0.9.7. 25 | 26 | ### v0.9.7 27 | 28 | - Fix a corner case where modules could appear in the build config's `paths`. 29 | - Fix regressions introduced in v0.9.6. 30 | - Allow protocol relative urls for CDNs in the build config's `paths` (credit @remybach). 31 | 32 | ### v0.9.6 33 | 34 | - Update `require.js` and `r.js` to `2.1.17`, and `almond.js` to `0.3.1`. 35 | - Improve handling of Bower packages. 36 | - Make a small fix for Sprockets 3 support. 37 | 38 | ### v0.9.5 39 | 40 | - Update `require.js` and `r.js` to `2.1.15`, and `almond.js` to `0.3.0`. 41 | - Remove `data-main` attribute generation from `requirejs_include_tag` and replicate its functionality with an explicit 42 | `require` call. This paves the way for proper almond support. 43 | - Instead of disabling JS compression everywhere, only do so when staging `r.js` input files. This enables `require.js` 44 | itself to be compiled (or not) by the asset pipeline, like any other asset. 45 | - Add support for `bower.json` modules. 46 | 47 | ### v0.9.4 48 | 49 | - Restore compression of non-module JS assets if specified, including `require.js` itself. 50 | - Update `require.js` to `2.1.14`. 51 | 52 | ### v0.9.3 53 | 54 | - Add detection and proper handling of Bower-based modules. 55 | - Update `require.js` to `2.1.11` and `almond.js` to `0.2.9`. 56 | 57 | ### v0.9.2 58 | 59 | - Update `require.js` to `2.1.10` and `almond.js` to `0.2.5`. 60 | - Rails 4 support. 61 | 62 | ### v0.9.1 63 | 64 | - Updated to to require.js \ r.js 2.1.2, and almond 0.2.3 65 | 66 | ### v0.9.0 67 | 68 | - **BREAKING CHANGE**: Upgrade RequireJS and r.js to v2.0.0 69 | - order.js was removed. See the new [RequireJS 2.0 shim config](https://github.com/jrburke/requirejs/wiki/Upgrading-to-RequireJS-2.0#wiki-shim). 70 | - Build support for `empty:` is now handled by r.js 2.0 natively. 71 | 72 | ### v0.8.2 73 | 74 | - Fix for `requirejs_include_tag` error when `config/requirejs.yml` has no 75 | `paths` key. Thanks to @JustinLove for the issue and failing test! 76 | 77 | ### v0.8.0 78 | 79 | - Build will now substitute `empty:` for the right-hand side of 80 | `config/requirejs.yml` paths entries that are URLs. 81 | - Documented how to configure assets hosted on a CDN. 82 | 83 | ### v0.7.3 84 | 85 | - Upgrade RequireJS and r.js to v1.0.8 86 | 87 | ### v0.7.2 88 | 89 | - Add require.js to config.assets.precompile in all environments. Closes #45. 90 | This change allows builds to work in Rails environments other than 91 | 'production', e.g. 'staging'. Thanks to @hollow for the fix. 92 | 93 | ### v0.7.1 94 | 95 | - Liberalize asset path filtering. `0.7.0` added filtering on the logical 96 | asset path which was too aggressive in that only `.js` files were allowed in 97 | builds. The RequireJS config variable `logical_asset_filter` has been 98 | added, which allows `.js`, `.html`, `.txt` files by default and is user 99 | configurable. 100 | 101 | ### v0.7.0 102 | 103 | - Support for [almond](https://github.com/jrburke/almond) via 104 | `config.requirejs.loader = :almond` in application.rb. 105 | - Builds with `config.assets.initialize_on_precompile = false` now work. 106 | This supports building on Heroku, builds with Devise, etc. all of 107 | which require that setting. 108 | - We should now play much better with existing Rails Engines that 109 | leverage the asset pipeline for their needs. Thanks to @hollow for the 110 | patch. 111 | 112 | ### v0.6.1 113 | 114 | - Fix regression in production env when `paths` specified in requirejs.yml. 115 | 116 | ### v0.6.0 117 | 118 | **NOTE:** Upgrade to 0.6.1! This was yanked due to a regression. 119 | 120 | - We now generate a paths config to hit digested assets when needed (in 121 | `production` or when `config.assets.digest` is true). Fixes #20. 122 | - Support for generating additional data attributes on the require.js script 123 | tag via `requirejs_include_tag`. See [README](README.md) for details. Closes 124 | pull request #32; thanks to @hollow for the submission! 125 | 126 | ### v0.5.6 127 | 128 | - Upgrade to RequireJS and r.js 1.0.7 129 | 130 | ### v0.5.5 131 | 132 | - Support for Rails 3.2.x. Rails 3.1.x is also supported by this release. 133 | 134 | ### v0.5.4 135 | 136 | - Upgrade to RequireJS and r.js 1.0.5 137 | - Pull request #31, closes #30. Thanks @karelim! 138 | 139 | ### v0.5.3 140 | 141 | - Upgrade to RequireJS and r.js 1.0.4 142 | - Pulled #22, fix for asset compliation failure with no config/requirejs.yml. 143 | Thanks @arehberg! 144 | 145 | ### v0.5.2 146 | 147 | - Upgrade to RequireJS and r.js 1.0.3 148 | 149 | ### v0.5.1 150 | 151 | - This is a quick turn to fix an issue that could trigger an Anonymous mismatched define() error from require.js and/or r.js. 152 | 153 | The preferred way to use the helper tag is now with an argument, like 154 | so: 155 | 156 | ```erb 157 | <%= requirejs_include_tag "application" %> 158 | ``` 159 | 160 | This usage ensures that the above helper will correctly generate a 161 | data-main attribute for the script tag. The requirejs_include_tag 162 | helper still works without an argument, and won't generate data-main 163 | in that case. 164 | 165 | Thanks to Andrew de Andrade for the catch. 166 | 167 | ### v0.5.0 168 | 169 | - Precompilation via `rake assets:precompile` is now implemented. 170 | - gem configuration via application.js is deprecated. 171 | - Application-specific require.js configuration lives in `config/requirejs.yml`. 172 | - See [README](README.md) for updated usage details. 173 | 174 | ### v0.0.2 175 | 176 | - Fixed stupid problems with Rails::Engine instantiation. 177 | - Test improvements 178 | - Upgrade to RequireJS 1.0.2 179 | 180 | ### v0.0.1 181 | 182 | - Birthday! 183 | - This gem makes `require.js` and the `order.js` plugin available to the Rails 3 Asset Pipeline. 184 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # Declare your gem's dependencies in requirejs-rails.gemspec. 4 | # Bundler will treat runtime dependencies like base dependencies, and 5 | # development dependencies will be added by default to the :development group. 6 | gemspec 7 | 8 | group :development, :test do 9 | # jquery-rails is used by the dummy application 10 | gem "jquery-rails" 11 | 12 | # ExecJS is used by our tests 13 | gem "execjs" 14 | end 15 | 16 | # Declare any dependencies that are still in development here instead of in 17 | # your gemspec. These might include edge Rails or gems from your path or 18 | # Git. Remember to move these dependencies to your gemspec before releasing 19 | # your gem to rubygems.org. 20 | 21 | # To use debugger 22 | # gem 'ruby-debug19', :require => 'ruby-debug' 23 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | requirejs-rails (1.0.1) 5 | railties (>= 3.1.1) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (4.2.1) 11 | actionpack (= 4.2.1) 12 | actionview (= 4.2.1) 13 | activejob (= 4.2.1) 14 | mail (~> 2.5, >= 2.5.4) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | actionpack (4.2.1) 17 | actionview (= 4.2.1) 18 | activesupport (= 4.2.1) 19 | rack (~> 1.6) 20 | rack-test (~> 0.6.2) 21 | rails-dom-testing (~> 1.0, >= 1.0.5) 22 | rails-html-sanitizer (~> 1.0, >= 1.0.1) 23 | actionview (4.2.1) 24 | activesupport (= 4.2.1) 25 | builder (~> 3.1) 26 | erubis (~> 2.7.0) 27 | rails-dom-testing (~> 1.0, >= 1.0.5) 28 | rails-html-sanitizer (~> 1.0, >= 1.0.1) 29 | activejob (4.2.1) 30 | activesupport (= 4.2.1) 31 | globalid (>= 0.3.0) 32 | activemodel (4.2.1) 33 | activesupport (= 4.2.1) 34 | builder (~> 3.1) 35 | activerecord (4.2.1) 36 | activemodel (= 4.2.1) 37 | activesupport (= 4.2.1) 38 | arel (~> 6.0) 39 | activesupport (4.2.1) 40 | i18n (~> 0.7) 41 | json (~> 1.7, >= 1.7.7) 42 | minitest (~> 5.1) 43 | thread_safe (~> 0.3, >= 0.3.4) 44 | tzinfo (~> 1.1) 45 | arel (6.0.0) 46 | builder (3.2.2) 47 | erubis (2.7.0) 48 | execjs (2.5.2) 49 | globalid (0.3.5) 50 | activesupport (>= 4.1.0) 51 | i18n (0.7.0) 52 | jquery-rails (4.0.3) 53 | rails-dom-testing (~> 1.0) 54 | railties (>= 4.2.0) 55 | thor (>= 0.14, < 2.0) 56 | json (1.8.6) 57 | loofah (2.0.1) 58 | nokogiri (>= 1.5.9) 59 | mail (2.6.3) 60 | mime-types (>= 1.16, < 3) 61 | mime-types (2.5) 62 | mini_portile (0.6.2) 63 | minitest (5.6.1) 64 | nokogiri (1.6.6.2) 65 | mini_portile (~> 0.6.0) 66 | rack (1.6.0) 67 | rack-test (0.6.3) 68 | rack (>= 1.0) 69 | rails (4.2.1) 70 | actionmailer (= 4.2.1) 71 | actionpack (= 4.2.1) 72 | actionview (= 4.2.1) 73 | activejob (= 4.2.1) 74 | activemodel (= 4.2.1) 75 | activerecord (= 4.2.1) 76 | activesupport (= 4.2.1) 77 | bundler (>= 1.3.0, < 2.0) 78 | railties (= 4.2.1) 79 | sprockets-rails 80 | rails-deprecated_sanitizer (1.0.3) 81 | activesupport (>= 4.2.0.alpha) 82 | rails-dom-testing (1.0.6) 83 | activesupport (>= 4.2.0.beta, < 5.0) 84 | nokogiri (~> 1.6.0) 85 | rails-deprecated_sanitizer (>= 1.0.1) 86 | rails-html-sanitizer (1.0.2) 87 | loofah (~> 2.0) 88 | railties (4.2.1) 89 | actionpack (= 4.2.1) 90 | activesupport (= 4.2.1) 91 | rake (>= 0.8.7) 92 | thor (>= 0.18.1, < 2.0) 93 | rake (10.4.2) 94 | sprockets (3.0.3) 95 | rack (~> 1.0) 96 | sprockets-rails (2.2.4) 97 | actionpack (>= 3.0) 98 | activesupport (>= 3.0) 99 | sprockets (>= 2.8, < 4.0) 100 | sqlite3 (1.3.10) 101 | thor (0.19.1) 102 | thread_safe (0.3.5) 103 | tzinfo (1.2.2) 104 | thread_safe (~> 0.1) 105 | 106 | PLATFORMS 107 | ruby 108 | 109 | DEPENDENCIES 110 | execjs 111 | jquery-rails 112 | rails (>= 3.1.1) 113 | requirejs-rails! 114 | sqlite3 115 | 116 | BUNDLED WITH 117 | 1.16.0 118 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2011 John Whitley 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 4 | # RequireJS for Rails 5 | 6 | Integrates [RequireJS](http://requirejs.org/) into the Rails 3+ Asset Pipeline. 7 | 8 | **UPGRADE NOTES:** Users upgrading within the 0.x series should read the Changes section for relevant usage changes. We're pushing hard to 1.0, when the configuration and setup details will be declared stable. Until that time expect some bumps as things bake out. 9 | 10 | ## Usage 11 | 12 | 1. Add this to your Rails app's `Gemfile`: 13 | 14 | ``` 15 | gem 'requirejs-rails' 16 | ``` 17 | 18 | 2. Remove all Sprockets directives such as `//= require jquery` from `application.js` and elsewhere. Instead establish JavaScript dependencies using AMD-style `define()` and `require()` calls. 19 | 20 | 3. Use `requirejs_include_tag` at the top-level of your app's layout(s). Other modules will be pulled in dynamically by `require.js` in development and for production builds optimized by `r.js`. Here's a basic `app/views/layouts/application.html.erb` modified for `requirejs-rails`: 21 | 22 | ```erb 23 | 24 | 25 | 26 | Frobnitz Online 27 | <%= stylesheet_link_tag "application" %> 28 | <%= requirejs_include_tag "application" %> 29 | <%= csrf_meta_tags %> 30 | 31 | 32 | 33 | 34 | <%= yield %> 35 | 36 | 37 | 38 | ``` 39 | 40 | 4. Organize your JavaScript or CoffeeScript code into modules using `define()`: 41 | 42 | ```coffeescript 43 | # app/assets/javascripts/views/tweet_view.js.coffee 44 | 45 | define ['backbone'], (Backbone) -> 46 | class TweetView extends Backbone.View 47 | # ... 48 | ``` 49 | 50 | 5. Instantiate your app using `require()` from a top-level module such as `application.js`: 51 | 52 | ```coffeescript 53 | # app/assets/javascripts/application.js.coffee 54 | 55 | require ['jquery', 'backbone', 'TheApp'], ($, Backbone, TheApp) -> 56 | 57 | # Start up the app once the DOM is ready 58 | $ -> 59 | window.App = new TheApp() 60 | Backbone.history.start 61 | pushState: true 62 | window.App.start() 63 | ``` 64 | 65 | 6. When ready, build your assets for production deployment as usual. 66 | `requirejs-rails` defaults to a single-file build of `application.js`. 67 | Additional modules and r.js layered builds may be specified via 68 | `config/requirejs.yml`; see the Configuration section below. 69 | 70 | ```rake assets:precompile``` 71 | 72 | ## Configuration 73 | 74 | ### The Basics 75 | 76 | Configuration lives in `config/requirejs.yml`. These values are inspected and 77 | used by `requirejs-rails` and passed along as configuration for require.js and 78 | `r.js`. The default configuration declares `application.js` as the sole 79 | top-level module. This can be overridden by creating 80 | a `config/requirejs.yml`, such as: 81 | 82 | ```yaml 83 | modules: 84 | - name: 'mytoplevel' 85 | ``` 86 | 87 | You may pass in [require.js config 88 | options](http://requirejs.org/docs/api.html#config) as needed. For example, 89 | to add path parameters: 90 | 91 | ```yaml 92 | paths: 93 | d3: "d3/d3" 94 | "d3.time": "d3/d3.time" 95 | ``` 96 | 97 | ### Layered builds 98 | 99 | Only modules specified in the configuration will be created as build artifacts 100 | by `r.js`. [Layered r.js 101 | builds](http://requirejs.org/docs/faq-optimization.html#priority) be 102 | configured like so: 103 | 104 | ```yaml 105 | modules: 106 | - name: 'appcommon' 107 | - name: 'page1' 108 | exclude: ['appcommon'] 109 | - name: 'page2' 110 | exclude: ['appcommon'] 111 | priority: ['appcommon'] 112 | ``` 113 | 114 | In this example, only modules `page1` and `page2` are intended for direct 115 | loading via `requirejs_include_tag`. The `appcommon` module contains 116 | dependencies shared by the per-page modules. As a guideline, each module in 117 | the configuration should be referenced by one of: 118 | 119 | - A `requirejs_include_tag` in a template 120 | - Pulled in via a dynamic `require()` call. Modules which are solely 121 | referenced by a dynamic `require()` call (i.e. a call not optimized by r.js) 122 | **must** be specified in the modules section in order to produce a correct 123 | build. 124 | - Be a common library module like `appcommon`, listed in the `priority` config 125 | option. 126 | 127 | ### Almond support 128 | 129 | This gem supports single-file builds with 130 | [almond](https://github.com/jrburke/almond). Use the following setting in 131 | `application.rb` to enable it: 132 | 133 | ```ruby 134 | config.requirejs.loader = :almond 135 | ``` 136 | 137 | Almond builds have the restriction that there must be exactly one `modules` entry in 138 | `requirejs.yml`. Typically the [wrap option](https://github.com/jrburke/r.js/blob/master/build/example.build.js#L275) will be used to create a self-contained build: 139 | 140 | ```yaml 141 | modules: 142 | - name: 'main' 143 | wrap: true 144 | ``` 145 | 146 | ### Build-time asset filter 147 | 148 | The `requirejs-rails` build process uses the Asset Pipeline to assemble assets 149 | for the `r.js` build. By default, assets ending in `.js`, `.html`, and `.txt` 150 | will be made available to the build. If you have other asset suffixes to 151 | include, use the `logical_path_patterns` config setting to add them. 152 | 153 | For example, if your templates all end in `.templ` like so... 154 | 155 | ```javascript 156 | // in app/assets/javascripts/myapp.js 157 | define(function (require) { 158 | var stuff = require('text!stuff.templ'); 159 | // ... 160 | }); 161 | ``` 162 | 163 | ... then this config setting will ensure they're picked up in the build: 164 | 165 | ```ruby 166 | # in config/application.rb 167 | config.requirejs.logical_path_patterns += [/\.templ$/] 168 | ``` 169 | 170 | ## Advanced features 171 | 172 | ### Additional data attributes 173 | 174 | `requirejs_include_tag` accepts an optional block which should return a hash. 175 | This hash will be used to populate additional `data-...` attributes like so: 176 | 177 | ```erb 178 | <%= requirejs_include_tag "page1" do |controller| 179 | { 'foo' => controller.foo, 180 | 'bar' => controller.bar 181 | } 182 | end 183 | %> 184 | ``` 185 | 186 | This will generate a script tag like so: 187 | 188 | ``` 189 | 190 | ``` 191 | 192 | ### External domain (CDN) support 193 | 194 | There are two ways in which requirejs-rails supports the use of different 195 | domains for serving built JavaScript modules, as is the case when using 196 | a [CDN](http://en.wikipedia.org/wiki/Content_delivery_network). 197 | 198 | 1. URLs in paths config in `requirejs.yml`: 199 | 200 | If requirejs-rails encounters an URL as the right-hand side of a paths 201 | configuration, it will correctly emit that as `"empty:"` during the build 202 | process so that [r.js will do the right thing](http://requirejs.org/docs/optimization.html#empty). 203 | 204 | Example: 205 | 206 | ```yaml 207 | paths: 208 | jquery: "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" 209 | ``` 210 | 211 | 2. Deploying all requirejs-rails assets to a CDN: 212 | 213 | In `config/environments/production.rb` (or another environment) 214 | set the run_config as follows: 215 | 216 | ```ruby 217 | config.requirejs.run_config['baseUrl'] = 'http://mycdn.example.com/12345abc/assets' 218 | ``` 219 | 220 | The [`asset_sync` gem](https://github.com/rumblelabs/asset_sync) is one 221 | tool that can be used to deploy your built assets to a CDN (S3, in this 222 | case). 223 | 224 | ## Troubleshooting 225 | 226 | ### Avoid `config.assets.precompile` 227 | 228 | Don't set `config.assets.precompile` to reference any of your AMD module code. 229 | Avoid it altogether, except to reference non-AMD code that you're loading via 230 | javascript_include_tag, and which is **never** referenced by the AMD codebase. 231 | 232 | ## Using AMD libraries 233 | 234 | I currently recommend placing your AMD libraries into 235 | `vendor/assets/javascripts`. The needs of a few specific libraries are 236 | discussed below. 237 | 238 | ### jQuery 239 | 240 | jQuery users must use jQuery 1.7 or later (`jquery-rails >= 1.0.17`) to use it as an [AMD module](https://github.com/amdjs/amdjs-api/wiki/AMD) with RequireJS. To use jQuery in a module: 241 | 242 | ```coffeescript 243 | # app/assets/javascripts/hello.js 244 | 245 | define ['jquery'], ($) -> 246 | (id) -> 247 | $(id).append('
hello!
') 248 | ``` 249 | 250 | ### Backbone.js 251 | 252 | Backbone 0.9.x doesn't support AMD natively. I recommend the [amdjs 253 | fork of Backbone](https://github.com/amdjs/backbone/) which adds AMD 254 | support and actively tracks mainline. 255 | 256 | ### Underscore.js 257 | 258 | Underscore 1.3.x likewise doesn't have AMD support. Again, see 259 | the [amdjs fork of Underscore](https://github.com/amdjs/underscore). 260 | 261 | ## 0.x API Changes 262 | 263 | Usage changes that may break functionality for those upgrading along the 0.x 264 | series are documented here. See [the Changelog](https://github.com/jwhitley/requirejs-rails/blob/master/CHANGELOG.md) for the full 265 | list of feature additions, bugfixes, etc. 266 | 267 | ### v0.9.2 268 | 269 | - Support for Rails 4. 270 | 271 | ### v0.9.0 272 | 273 | - The upgrade to RequireJS and r.js 2.0 includes changes that will break some 274 | apps. 275 | 276 | ### v0.5.1 277 | 278 | - `requirejs_include_tag` now generates a data-main attribute if given an argument, ala: 279 | 280 | ```erb 281 | <%= requirejs_include_tag "application" %> 282 | ``` 283 | 284 | This usage is preferred to using a separate 285 | `javascript_include_tag`, which will produce errors from require.js or 286 | r.js if the included script uses define anonymously, or not at all. 287 | 288 | ### v0.5.0 289 | 290 | - `application.js` is configured as the default top-level module for r.js builds. 291 | - It is no longer necessary or desirable to specify `baseUrl` explicitly in the configuration. 292 | - Users should migrate application configuration previously in `application.js` (ala `require.config(...)`) to `config/requirejs.yml` 293 | 294 | 295 | 296 | ## TODOs 297 | 298 | Please check out [our GitHub issues page](https://github.com/jwhitley/requirejs-rails/issues) 299 | to see what's upcoming and to file feature requests and bug reports. 300 | 301 | ---- 302 | 303 | Copyright 2011-2014 John Whitley. See the file MIT-LICENSE for terms. 304 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | begin 3 | require 'bundler/setup' 4 | rescue LoadError 5 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks' 6 | end 7 | begin 8 | require 'rdoc/task' 9 | rescue LoadError 10 | require 'rdoc/rdoc' 11 | require 'rake/rdoctask' 12 | RDoc::Task = Rake::RDocTask 13 | end 14 | 15 | RDoc::Task.new(:rdoc) do |rdoc| 16 | rdoc.rdoc_dir = 'rdoc' 17 | rdoc.title = 'RequirejsRails' 18 | rdoc.options << '--line-numbers' 19 | rdoc.rdoc_files.include('README.rdoc') 20 | rdoc.rdoc_files.include('lib/**/*.rb') 21 | end 22 | 23 | 24 | 25 | Bundler::GemHelper.install_tasks 26 | 27 | require 'rake/testtask' 28 | 29 | Rake::TestTask.new(:test) do |t| 30 | t.libs << 'lib' 31 | t.libs << 'test' 32 | t.pattern = 'test/**/*_test.rb' 33 | t.verbose = false 34 | end 35 | 36 | 37 | task :default => :test 38 | -------------------------------------------------------------------------------- /app/helpers/requirejs_helper.rb: -------------------------------------------------------------------------------- 1 | require "requirejs/error" 2 | require "requirejs/rails/view" 3 | 4 | module RequirejsHelper 5 | def self.included(clazz) 6 | clazz.class_eval do 7 | extend Forwardable 8 | 9 | # Delegate all JavaScript path queries to the specially modified internal view. 10 | def_delegators :view, :javascript_path 11 | end 12 | end 13 | 14 | # EXPERIMENTAL: Additional priority settings appended to 15 | # any user-specified priority setting by requirejs_include_tag. 16 | # Used for JS test suite integration. 17 | mattr_accessor :_priority 18 | @@_priority = [] 19 | 20 | def requirejs_include_tag(name = nil, &block) 21 | requirejs = Rails.application.config.requirejs 22 | 23 | if requirejs.loader == :almond 24 | name = requirejs.module_name_for(requirejs.build_config['modules'][0]) 25 | return almond_include_tag(name, &block) 26 | end 27 | 28 | html = "" 29 | 30 | once_guard do 31 | rjs_attributes = { 32 | src: [host_url, javascript_path("require")].join 33 | } 34 | 35 | rjs_attributes = rjs_attributes.merge(Hash[block.call(controller).map do |key, value| 36 | ["data-#{key}", value] 37 | end]) \ 38 | if block 39 | 40 | html.concat(content_tag(:script, "", rjs_attributes)) 41 | 42 | unless requirejs.run_config.empty? 43 | run_config = requirejs.run_config.dup 44 | 45 | unless _priority.empty? 46 | run_config = run_config.dup 47 | run_config[:priority] ||= [] 48 | run_config[:priority].concat _priority 49 | end 50 | 51 | if Rails.application.config.assets.digest 52 | assets_precompiled = !Rails.application.config.assets.compile 53 | modules = requirejs.build_config["modules"].map {|m| requirejs.module_name_for m} 54 | user_paths = requirejs.build_config["paths"] || {} 55 | 56 | # Generate digestified paths from the modules spec 57 | paths = {} 58 | 59 | modules.each do |module_name| 60 | script_path = if !assets_precompiled 61 | # If modules haven't been precompiled, search for them based on their user-defined paths before using the 62 | # module name. 63 | user_paths[module_name] || module_name 64 | else 65 | # If modules have been precompiled, the script path is just the module name. 66 | module_name 67 | end 68 | 69 | normalized_script_path = javascript_path(script_path).gsub(/\.js$/, "") 70 | 71 | if !host_url 72 | paths[module_name] = normalized_script_path 73 | else 74 | paths[module_name] = [host_url, normalized_script_path].join 75 | end 76 | end 77 | 78 | if run_config.has_key? "paths" 79 | # Add paths for assets specified by full URL (on a CDN) 80 | run_config["paths"].each do |k, v| 81 | paths[k] = v if v.is_a?(Array) || v =~ /^(https?:)?\/\// 82 | end 83 | end 84 | 85 | # Override user paths, whose mappings are only relevant in dev mode 86 | # and in the build_config. 87 | run_config["paths"] = paths 88 | end 89 | 90 | run_config["baseUrl"] = [host_url, Rails.application.config.assets.prefix].join 91 | 92 | html.concat(content_tag(:script) do 93 | script = "require.config(#{run_config.to_json});" 94 | 95 | # Pass an array to `require`, since it's a top-level module about to be loaded asynchronously (see 96 | # `http://requirejs.org/docs/errors.html#notloaded`). 97 | script.concat(" require([#{name.dump}]);") \ 98 | if name 99 | 100 | script.html_safe 101 | end) 102 | end 103 | 104 | html.html_safe 105 | end 106 | end 107 | 108 | private 109 | 110 | def once_guard 111 | if defined?(controller) && controller.requirejs_included 112 | raise Requirejs::MultipleIncludeError, "Only one requirejs_include_tag allowed per page." 113 | end 114 | 115 | retval = yield 116 | 117 | controller.requirejs_included = true if defined?(controller) 118 | retval 119 | end 120 | 121 | def almond_include_tag(name, &block) 122 | content_tag(:script, "", src: [host_url, javascript_path(name)].join) 123 | end 124 | 125 | # Retrieve where the assets are hosted. Assume the root path if `nil`. 126 | def host_url 127 | config = Rails.application.config 128 | action_controller_config = config.action_controller 129 | asset_host = action_controller_config.asset_host 130 | 131 | @host_url ||= if !asset_host 132 | action_controller_config.relative_url_root 133 | else 134 | asset_host 135 | end 136 | end 137 | 138 | def view 139 | @view ||= Requirejs::Rails::View.new 140 | end 141 | end 142 | -------------------------------------------------------------------------------- /lib/requirejs-rails.rb: -------------------------------------------------------------------------------- 1 | require "requirejs/rails" 2 | -------------------------------------------------------------------------------- /lib/requirejs/error.rb: -------------------------------------------------------------------------------- 1 | module Requirejs 2 | # Raised if requirejs_include_tag appears multiple times on a page. 3 | class MultipleIncludeError < RuntimeError; end 4 | # Raised if the configuration fails validation. 5 | class ConfigError < ArgumentError; end 6 | # Raised if the builder encounters an error. 7 | class BuildError < RuntimeError; end 8 | end 9 | -------------------------------------------------------------------------------- /lib/requirejs/rails.rb: -------------------------------------------------------------------------------- 1 | module Requirejs 2 | module Rails 3 | require "requirejs/rails/engine" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/requirejs/rails/builder.rb: -------------------------------------------------------------------------------- 1 | require "ostruct" 2 | require "pathname" 3 | 4 | require "requirejs/rails" 5 | 6 | module Requirejs 7 | module Rails 8 | class Builder 9 | def initialize(config) 10 | @config = config 11 | end 12 | 13 | def build 14 | @config.tmp_dir 15 | end 16 | 17 | def generate_rjs_driver 18 | templ = Erubis::Eruby.new(@config.driver_template_path.read) 19 | @config.driver_path.open('w') do |f| 20 | f.write(templ.result(@config.get_binding)) 21 | end 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/requirejs/rails/config.rb: -------------------------------------------------------------------------------- 1 | require "pathname" 2 | 3 | require "active_support/ordered_options" 4 | require "erubis" 5 | 6 | require "requirejs/error" 7 | require "requirejs/rails" 8 | 9 | module Requirejs 10 | module Rails 11 | class Config < ::ActiveSupport::OrderedOptions 12 | LOADERS = [:requirejs, :almond] 13 | 14 | BOWER_PATH_PATTERN = Regexp.new("\\A(.*)/(?:\\.bower|bower|component)\\.json\\z") 15 | 16 | LOGICAL_PATH_PATTERNS = [ 17 | Regexp.new("\\.html\\z"), 18 | Regexp.new("\\.js\\z"), 19 | Regexp.new("\\.es6\\z"), 20 | Regexp.new("\\.txt\\z"), 21 | BOWER_PATH_PATTERN 22 | ] 23 | 24 | def initialize(application) 25 | super 26 | 27 | self.manifest = nil 28 | self.logical_path_patterns = LOGICAL_PATH_PATTERNS 29 | 30 | self.tmp_dir = application.root + 'tmp' 31 | self.bin_dir = Pathname.new(__FILE__ + '/../../../../bin').cleanpath 32 | 33 | self.source_dir = self.tmp_dir.join("requirejs/src") 34 | self.build_dir = self.tmp_dir.join("requirejs/dst") 35 | 36 | # This will be instantiated in the engine's `before_initialize` hook, because its default value is derived from 37 | # the app's configuration. 38 | self.target_dir = nil 39 | 40 | self.rjs_path = self.bin_dir + 'r.js' 41 | 42 | self.loader = :requirejs 43 | 44 | self.driver_template_path = Pathname.new(__FILE__ + '/../rjs_driver.js.erb').cleanpath 45 | self.driver_path = self.tmp_dir.join("requirejs/rjs_driver.js") 46 | 47 | self.user_config = {} 48 | 49 | self.run_config_whitelist = %w{ 50 | baseUrl 51 | callback 52 | catchError 53 | config 54 | context 55 | deps 56 | jQuery 57 | locale 58 | map 59 | packages 60 | paths 61 | priority 62 | scriptType 63 | shim 64 | urlArgs 65 | waitSeconds 66 | xhtml 67 | } 68 | 69 | self.build_config_whitelist = %w{ 70 | appDir 71 | baseUrl 72 | closure 73 | cssImportIgnore 74 | cssIn 75 | dir 76 | fileExclusionRegExp 77 | findNestedDependencies 78 | has 79 | hasOnSave 80 | include 81 | inlineText 82 | locale 83 | mainConfigFile 84 | map 85 | modules 86 | name 87 | namespace 88 | onBuildRead 89 | onBuildWrite 90 | optimize 91 | optimizeAllPluginResources 92 | optimizeCss 93 | out 94 | packagePaths 95 | packages 96 | paths 97 | pragmas 98 | pragmasOnSave 99 | preserveLicenseComments 100 | shim 101 | skipModuleInsertion 102 | skipPragmas 103 | uglify 104 | uglify2 105 | useStrict 106 | wrap 107 | wrapShim 108 | } 109 | end 110 | 111 | def loader=(sym) 112 | unless LOADERS.include?(sym) 113 | raise Requirejs::ConfigError, "Attempt to set unknown loader: #{sym}" 114 | end 115 | self[:loader] = sym 116 | end 117 | 118 | def build_config 119 | unless self.has_key?(:build_config) 120 | self[:build_config] = self.run_config.merge "baseUrl" => source_dir.to_s, 121 | "modules" => [{'name' => 'application'}] 122 | self[:build_config].merge!(self.user_config).slice!(*self.build_config_whitelist) 123 | case self.loader 124 | when :requirejs 125 | # nothing to do 126 | when :almond 127 | mods = self[:build_config]['modules'] 128 | unless mods.length == 1 129 | raise Requirejs::ConfigError, "Almond build requires exactly one module, config has #{mods.length}." 130 | end 131 | mod = mods[0] 132 | name = mod['name'] 133 | mod['name'] = 'almond' 134 | mod['include'] = name 135 | end 136 | end 137 | self[:build_config] 138 | end 139 | 140 | def run_config 141 | unless self.has_key?(:run_config) 142 | self[:run_config] = {"baseUrl" => "/assets"} 143 | self[:run_config].merge!(self.user_config).slice!(*self.run_config_whitelist) 144 | end 145 | self[:run_config] 146 | end 147 | 148 | def user_config=(cfg) 149 | if url = cfg.delete('baseUrl') 150 | raise Requirejs::ConfigError, "baseUrl is not needed or permitted in the configuration" 151 | end 152 | self[:user_config] = cfg 153 | end 154 | 155 | def module_name_for(mod) 156 | case self.loader 157 | when :almond 158 | return mod['include'] 159 | when :requirejs 160 | return mod['name'] 161 | end 162 | end 163 | 164 | def get_binding 165 | return binding() 166 | end 167 | end 168 | end 169 | end 170 | -------------------------------------------------------------------------------- /lib/requirejs/rails/engine.rb: -------------------------------------------------------------------------------- 1 | require "pathname" 2 | 3 | require "requirejs/rails/config" 4 | require "requirejs/rails/view" 5 | 6 | module Requirejs 7 | module Rails 8 | class Engine < ::Rails::Engine 9 | ### Configuration setup 10 | config.before_configuration do |app| 11 | config.requirejs = Requirejs::Rails::Config.new(app) 12 | config.requirejs.precompile = [/require\.js$/] 13 | end 14 | 15 | config.before_initialize do |app| 16 | config = app.config 17 | 18 | # Process the user config file in #before_initalization (instead of #before_configuration) so that 19 | # environment-specific configuration can be injected into the user configuration file 20 | Engine.process_user_config_file(app, config) 21 | 22 | config.assets.precompile += config.requirejs.precompile 23 | 24 | # Check for the `requirejs:precompile:all` top-level Rake task and run the following initialization code. 25 | if defined?(Rake.application) && Rake.application.top_level_tasks == ["requirejs:precompile:all"] 26 | # Prevent Sprockets from freezing the assets environment, which allows JS compression to be toggled on a per- 27 | # file basis. This trick *will* fail if any of the lines linked to below change. 28 | 29 | if ::Rails::VERSION::MAJOR >= 4 30 | # For Rails 4 (see 31 | # `https://github.com/rails/sprockets-rails/blob/v2.1.2/lib/sprockets/railtie.rb#L119-121`). 32 | config.cache_classes = false 33 | else 34 | # For Rails 3 (see 35 | # `https://github.com/rails/rails/blob/v3.2.19/actionpack/lib/sprockets/bootstrap.rb#L32-34`). 36 | config.assets.digest = false 37 | end 38 | end 39 | 40 | manifest_directory = if config.assets.manifest 41 | File.basename(config.assets.manifest) =~ /\./ ? File.dirname(config.assets.manifest) : config.assets.manifest 42 | else 43 | File.join(::Rails.public_path, config.assets.prefix) 44 | end 45 | 46 | manifest_path = File.join(manifest_directory, "rjs_manifest.yml") 47 | config.requirejs.manifest_path = Pathname.new(manifest_path) 48 | 49 | config.requirejs.target_dir ||= app.root + "public" + 50 | Pathname.new(config.assets.prefix).relative_path_from(Pathname.new("/")) 51 | end 52 | 53 | ### Initializers 54 | initializer "requirejs.tag_included_state" do |app| 55 | ActiveSupport.on_load(:action_controller) do 56 | ::ActionController::Base.class_eval do 57 | attr_accessor :requirejs_included 58 | end 59 | end 60 | end 61 | 62 | # Are we running in the precompilation Rake task? If so, we need to adjust certain environmental configuration 63 | # values. 64 | if defined?(Rake.application) && Rake.application.top_level_tasks.include?("requirejs:precompile:all") 65 | initializer "requirejs.modify_environment_config", after: "load_environment_config", group: :all do |app| 66 | app.configure do 67 | # If we don't set this to true, sprockets-rails will assign `Rails.application.assets` to `nil`. 68 | config.assets.compile = true 69 | 70 | # Don't compress JavaScripts fed into the r.js optimizer. 71 | config.assets.js_compressor = false 72 | 73 | # Don't use any cache to retrieve assets. 74 | config.assets.cache = nil 75 | end 76 | end 77 | end 78 | 79 | if ::Rails::VERSION::MAJOR >= 4 80 | config.after_initialize do |app| 81 | config = app.config 82 | if config.requirejs.manifest_path.exist? 83 | rails_manifest = ::Sprockets::Railtie.build_manifest(app) 84 | rjs_digests = YAML.load(ERB.new(File.new(config.requirejs.manifest_path).read).result) 85 | rails_manifest.assets.merge!(rjs_digests) 86 | ActionView::Base.instance_eval do 87 | self.assets_manifest = rails_manifest 88 | end 89 | end 90 | 91 | # This allows requirejs-rails to serve up modules by their undigestified asset paths. 92 | Requirejs::Rails::View.instance_eval do 93 | self.check_precompiled_asset = false 94 | end 95 | end 96 | else 97 | initializer "requirejs.manifest", :after => "sprockets.environment" do |app| 98 | config = app.config 99 | if config.requirejs.manifest_path.exist? && config.assets.digests 100 | rjs_digests = YAML.load(ERB.new(File.new(config.requirejs.manifest_path).read).result) 101 | config.assets.digests.merge!(rjs_digests) 102 | end 103 | end 104 | end 105 | 106 | # Process the user-supplied config parameters, which will be 107 | # merged with the default params. It should be a YAML file with 108 | # a single top-level hash, keys/values corresponding to require.js 109 | # config parameters. 110 | def self.process_user_config_file(app, config) 111 | config_path = Pathname.new(app.paths["config"].first) 112 | config.requirejs.user_config_file = config_path + 'requirejs.yml' 113 | 114 | yaml_file_contents = nil 115 | if config.requirejs.user_config_file.exist? 116 | yaml_file_contents = config.requirejs.user_config_file.read 117 | else 118 | # if requirejs.yml doesn't exist, look for requirejs.yml.erb and process it as an erb 119 | config.requirejs.user_config_file = config_path + 'requirejs.yml.erb' 120 | 121 | if config.requirejs.user_config_file.exist? 122 | yaml_file_contents = ERB.new(config.requirejs.user_config_file.read).result 123 | end 124 | end 125 | 126 | if yaml_file_contents.nil? 127 | # If we couldn't find any matching file contents to process, empty user config 128 | config.requirejs.user_config = {} 129 | else 130 | config.requirejs.user_config = YAML.load(yaml_file_contents) 131 | end 132 | end 133 | end # class Engine 134 | end 135 | end 136 | -------------------------------------------------------------------------------- /lib/requirejs/rails/rjs_driver.js.erb: -------------------------------------------------------------------------------- 1 | var requirejs = require(<%= rjs_path.to_s.dump %>) 2 | var baseConfig = <%= 3 | cdn_pattern = Regexp.new("\\Ahttps?://") 4 | 5 | modifiedHash = build_config.select { |k, _| k != "modules" } 6 | pathsHash = modifiedHash["paths"] 7 | 8 | case loader 9 | when :requirejs 10 | modifiedHash['dir'] = build_dir.to_s 11 | when :almond 12 | almond_module = build_config['modules'][0] 13 | modifiedHash.merge!(almond_module) 14 | modifiedHash['out'] = build_dir + (module_name_for(almond_module) + '.js') 15 | end 16 | 17 | modifiedHash["paths"] = Hash[ 18 | pathsHash.map do |k, v| 19 | [k, v.is_a?(Array) || cdn_pattern.match(v) ? "empty:" : v] 20 | end 21 | ] if !pathsHash.nil? 22 | 23 | JSON.pretty_generate(modifiedHash) 24 | %>; 25 | 26 | <% unless loader == :almond %> 27 | baseConfig.modules = [ 28 | <% build_config["modules"].each do |m| %> 29 | <%= JSON.pretty_generate(m) %>, 30 | <% end %> 31 | ]; 32 | <% end %> 33 | 34 | requirejs.optimize(baseConfig); 35 | -------------------------------------------------------------------------------- /lib/requirejs/rails/version.rb: -------------------------------------------------------------------------------- 1 | module Requirejs 2 | module Rails 3 | Version = "1.0.1" 4 | LibVersion = "2.1.22" 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /lib/requirejs/rails/view.rb: -------------------------------------------------------------------------------- 1 | module Requirejs 2 | module Rails 3 | class View < ::ActionView::Base 4 | end 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /lib/tasks/requirejs-rails_tasks.rake: -------------------------------------------------------------------------------- 1 | require "fileutils" 2 | require "pathname" 3 | require "tempfile" 4 | 5 | require "active_support/ordered_options" 6 | require "sprockets" 7 | 8 | require "requirejs/rails/builder" 9 | require "requirejs/rails/config" 10 | 11 | namespace :requirejs do 12 | # This method was backported from an earlier version of Sprockets. 13 | def ruby_rake_task(task, force = true) 14 | env = ENV["RAILS_ENV"] || "production" 15 | groups = ENV["RAILS_GROUPS"] || "assets" 16 | args = [$0, task, "RAILS_ENV=#{env}", "RAILS_GROUPS=#{groups}"] 17 | args << "--trace" if Rake.application.options.trace 18 | ruby *args 19 | end 20 | 21 | # From Rails 3 assets.rake; we have the same problem: 22 | # 23 | # We are currently running with no explicit bundler group 24 | # and/or no explicit environment - we have to reinvoke rake to 25 | # execute this task. 26 | def invoke_or_reboot_rake_task(task) 27 | if ENV['RAILS_GROUPS'].to_s.empty? || ENV['RAILS_ENV'].to_s.empty? 28 | ruby_rake_task task 29 | else 30 | Rake::Task[task].invoke 31 | end 32 | end 33 | 34 | requirejs = ActiveSupport::OrderedOptions.new 35 | path_extension_pattern = Regexp.new("\\.(\\w+)\\z") 36 | 37 | task clean: ["requirejs:setup"] do 38 | FileUtils.remove_entry_secure(requirejs.config.source_dir, true) 39 | FileUtils.remove_entry_secure(requirejs.driver_path, true) 40 | end 41 | 42 | task setup: ["assets:environment"] do 43 | unless defined?(::Sprockets) 44 | warn "Cannot precompile assets if sprockets is disabled. Please set config.assets.enabled to true" 45 | exit 46 | end 47 | 48 | # Ensure that action view is loaded and the appropriate 49 | # sprockets hooks get executed 50 | _ = ActionView::Base 51 | 52 | requirejs.env = Rails.application.assets 53 | 54 | # Preserve the original asset paths, as we'll be manipulating them later 55 | requirejs.env_paths = requirejs.env.paths.dup 56 | requirejs.config = Rails.application.config.requirejs 57 | requirejs.builder = Requirejs::Rails::Builder.new(requirejs.config) 58 | requirejs.manifest = {} 59 | end 60 | 61 | task :test_node do 62 | begin 63 | `node -v` 64 | rescue Errno::ENOENT 65 | STDERR.puts <<-EOM 66 | Unable to find 'node' on the current path, required for precompilation 67 | using the requirejs-ruby gem. To install node.js, see http://nodejs.org/ 68 | OS X Homebrew users can use 'brew install node'. 69 | EOM 70 | exit 1 71 | end 72 | end 73 | 74 | namespace :precompile do 75 | task all: ["requirejs:precompile:digestify_and_compress"] 76 | 77 | # Invoke another ruby process if we're called from inside 78 | # assets:precompile so we don't clobber the environment 79 | # 80 | # We depend on test_node here so we'll fail early and hard if node 81 | # isn't available. 82 | task :external do 83 | ruby_rake_task "requirejs:precompile:all" 84 | end 85 | 86 | # Copy all assets to the temporary staging directory. 87 | task prepare_source: ["requirejs:setup", 88 | "requirejs:clean"] do 89 | requirejs.config.source_dir.mkpath 90 | 91 | requirejs.env.each_logical_path(requirejs.config.logical_path_patterns) do |logical_path| 92 | m = ::Requirejs::Rails::Config::BOWER_PATH_PATTERN.match(logical_path) 93 | 94 | if !m 95 | asset = requirejs.env.find_asset(logical_path) 96 | 97 | if asset 98 | file = requirejs.config.source_dir.join(asset.logical_path) 99 | file.dirname.mkpath 100 | asset.write_to(file) 101 | end 102 | else 103 | bower_logical_path = "#{Pathname.new(logical_path).dirname.to_s}.js" 104 | asset = requirejs.env.find_asset(bower_logical_path) 105 | 106 | if asset 107 | file = requirejs.config.source_dir.join(bower_logical_path) 108 | file.dirname.mkpath 109 | asset.write_to(file) 110 | end 111 | end 112 | end 113 | end 114 | 115 | task generate_rjs_driver: ["requirejs:setup"] do 116 | requirejs.builder.generate_rjs_driver 117 | end 118 | 119 | task run_rjs: ["requirejs:setup", 120 | "requirejs:test_node", 121 | "requirejs:precompile:prepare_source", 122 | "requirejs:precompile:generate_rjs_driver"] do 123 | requirejs.config.build_dir.mkpath 124 | requirejs.config.target_dir.mkpath 125 | requirejs.config.driver_path.dirname.mkpath 126 | 127 | result = `node "#{requirejs.config.driver_path}"` 128 | unless $?.success? 129 | raise RuntimeError, "Asset compilation with node failed with error:\n\n#{result}\n" 130 | end 131 | end 132 | 133 | # Copy each built asset, identified by a named module in the 134 | # build config, to its Sprockets digestified name. 135 | task digestify_and_compress: ["requirejs:precompile:run_rjs"] do 136 | requirejs.config.build_config["modules"].each do |m| 137 | module_name = requirejs.config.module_name_for(m) 138 | paths = requirejs.config.build_config["paths"] || {} 139 | module_script_name = "#{module_name}.js" 140 | 141 | # Is there a `paths` entry for the module? 142 | if !paths[module_name] 143 | asset_name = module_script_name 144 | else 145 | asset_name = "#{paths[module_name]}.js" 146 | end 147 | 148 | asset = requirejs.env.find_asset(asset_name) 149 | 150 | built_asset_path = requirejs.config.build_dir.join(asset_name) 151 | 152 | # Compute the digest based on the contents of the compiled file, *not* on the contents of the RequireJS module. 153 | file_digest = requirejs.env.file_digest(built_asset_path.to_s) 154 | hex_digest = file_digest.unpack("H*").first 155 | digest_name = asset.logical_path.gsub(path_extension_pattern) { |ext| "-#{hex_digest}#{ext}" } 156 | 157 | digest_asset_path = requirejs.config.target_dir + digest_name 158 | 159 | # Ensure that the parent directory `a/b` for modules with names like `a/b/c` exist. 160 | digest_asset_path.dirname.mkpath 161 | 162 | requirejs.manifest[module_script_name] = digest_name 163 | FileUtils.cp built_asset_path, digest_asset_path 164 | 165 | # Create the compressed versions 166 | File.open("#{built_asset_path}.gz", 'wb') do |f| 167 | zgw = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION) 168 | zgw.write built_asset_path.read 169 | zgw.close 170 | end 171 | FileUtils.cp "#{built_asset_path}.gz", "#{digest_asset_path}.gz" 172 | 173 | manifest_path = requirejs.config.manifest_path 174 | manifest_path.dirname.mkpath 175 | 176 | manifest_path.open('wb') do |f| 177 | YAML.dump(requirejs.manifest, f) 178 | end 179 | end 180 | end 181 | end 182 | 183 | desc "Precompile RequireJS-managed assets" 184 | task :precompile do 185 | invoke_or_reboot_rake_task "requirejs:precompile:all" 186 | end 187 | end 188 | 189 | task "assets:precompile" => ["requirejs:precompile:external"] 190 | -------------------------------------------------------------------------------- /requirejs-rails.gemspec: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path("../lib", __FILE__) 2 | 3 | # Maintain your gem's version: 4 | require "requirejs/rails/version" 5 | 6 | # Describe your gem and declare its dependencies: 7 | Gem::Specification.new do |s| 8 | s.name = "requirejs-rails" 9 | s.version = Requirejs::Rails::Version 10 | s.authors = ["John Whitley"] 11 | s.email = ["whitley@bangpath.org"] 12 | s.homepage = "http://github.com/jwhitley/requirejs-rails" 13 | s.summary = "Use RequireJS with the Rails 3+ Asset Pipeline" 14 | s.description = "This gem provides RequireJS support for your Rails 3 application." 15 | 16 | git_test_files, git_files = `git ls-files`.split("\n").partition { |f| f =~ /^test/ } 17 | s.test_files = git_test_files 18 | s.files = git_files 19 | s.require_path = 'lib' 20 | 21 | s.add_dependency "railties", ">= 3.1.1" 22 | s.add_development_dependency "rails", ">= 3.1.1" 23 | s.add_development_dependency "sqlite3" 24 | 25 | s.requirements << "node.js is required for 'rake assets:precompile', used to run the r.js build" 26 | s.requirements << "If needed, jQuery should be v1.7 or greater (jquery-rails >= 1.0.17)." 27 | end 28 | -------------------------------------------------------------------------------- /test/dummy/.rvmrc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This is an RVM Project .rvmrc file, used to automatically load the ruby 4 | # development environment upon cd'ing into the directory 5 | 6 | # First we specify our desired [@], the @gemset name is optional. 7 | environment_id="ruby-1.9.3-p0@requirejs-rails" 8 | 9 | # 10 | # Uncomment following line if you want options to be set only for given project. 11 | # 12 | # PROJECT_JRUBY_OPTS=( --1.9 ) 13 | 14 | # 15 | # First we attempt to load the desired environment directly from the environment 16 | # file. This is very fast and efficient compared to running through the entire 17 | # CLI and selector. If you want feedback on which environment was used then 18 | # insert the word 'use' after --create as this triggers verbose mode. 19 | # 20 | if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \ 21 | && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]] 22 | then 23 | \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id" 24 | 25 | if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] 26 | then 27 | . "${rvm_path:-$HOME/.rvm}/hooks/after_use" 28 | fi 29 | else 30 | # If the environment file has not yet been created, use the RVM CLI to select. 31 | if ! rvm --create use "$environment_id" 32 | then 33 | echo "Failed to create RVM environment '${environment_id}'." 34 | return 1 35 | fi 36 | fi 37 | 38 | # 39 | # If you use an RVM gemset file to install a list of gems (*.gems), you can have 40 | # it be automatically loaded. Uncomment the following and adjust the filename if 41 | # necessary. 42 | # 43 | # filename=".gems" 44 | # if [[ -s "$filename" ]] 45 | # then 46 | # rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d' 47 | # fi 48 | 49 | # If you use bundler, this might be useful to you: 50 | # if command -v bundle && [[ -s Gemfile ]] 51 | # then 52 | # bundle install 53 | # fi 54 | 55 | 56 | -------------------------------------------------------------------------------- /test/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | Dummy::Application.load_tasks 8 | -------------------------------------------------------------------------------- /test/dummy/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into including all the files listed below. 2 | // Add new JavaScript/Coffee code in separate files in this directory and they'll automatically 3 | // be included in the compiled file accessible from http://example.com/assets/application.js 4 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 5 | // the compiled file. 6 | // 7 | //= require jquery 8 | //= require jquery_ujs 9 | //= require_tree . 10 | -------------------------------------------------------------------------------- /test/dummy/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll automatically include all the stylesheets available in this directory 3 | * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at 4 | * the top of the compiled file, but it's generally better to create a new file per style scope. 5 | *= require_self 6 | *= require_tree . 7 | */ -------------------------------------------------------------------------------- /test/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | end 4 | -------------------------------------------------------------------------------- /test/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /test/dummy/app/mailers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jwhitley/requirejs-rails/7a05a81d35f862becb859b5a8dd6968fb02da4d1/test/dummy/app/mailers/.gitkeep -------------------------------------------------------------------------------- /test/dummy/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jwhitley/requirejs-rails/7a05a81d35f862becb859b5a8dd6968fb02da4d1/test/dummy/app/models/.gitkeep -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | <%= stylesheet_link_tag "application" %> 6 | <%= javascript_include_tag "application" %> 7 | <%= csrf_meta_tags %> 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Dummy::Application 5 | -------------------------------------------------------------------------------- /test/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | Bundler.require 6 | require "requirejs-rails" 7 | 8 | module Dummy 9 | class Application < Rails::Application 10 | # Settings in config/environments/* take precedence over those specified here. 11 | # Application configuration should go into files in config/initializers 12 | # -- all .rb files in that directory are automatically loaded. 13 | 14 | # Custom directories with classes and modules you want to be autoloadable. 15 | # config.autoload_paths += %W(#{config.root}/extras) 16 | 17 | # Only load the plugins named here, in the order given (default is alphabetical). 18 | # :all can be used as a placeholder for all plugins not explicitly named. 19 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 20 | 21 | # Activate observers that should always be running. 22 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 23 | 24 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 25 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 26 | # config.time_zone = 'Central Time (US & Canada)' 27 | 28 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 29 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 30 | # config.i18n.default_locale = :de 31 | 32 | # Configure the default encoding used in templates for Ruby 1.9. 33 | config.encoding = "utf-8" 34 | 35 | # Configure sensitive parameters which will be filtered from the log file. 36 | config.filter_parameters += [:password] 37 | 38 | # Enable the asset pipeline 39 | config.assets.enabled = true 40 | 41 | # Version of your assets, change this if you want to expire all your assets 42 | config.assets.version = '1.0' 43 | end 44 | end 45 | 46 | -------------------------------------------------------------------------------- /test/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | gemfile = File.expand_path('../../../../Gemfile', __FILE__) 3 | 4 | if File.exist?(gemfile) 5 | ENV['BUNDLE_GEMFILE'] = gemfile 6 | require 'bundler' 7 | Bundler.setup 8 | end 9 | 10 | $:.unshift File.expand_path('../../../../lib', __FILE__) -------------------------------------------------------------------------------- /test/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | development: 7 | adapter: sqlite3 8 | database: db/development.sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | # Warning: The database defined as "test" will be erased and 13 | # re-generated from your development database when you run "rake". 14 | # Do not set this db to the same as development or production. 15 | test: 16 | adapter: sqlite3 17 | database: db/test.sqlite3 18 | pool: 5 19 | timeout: 5000 20 | 21 | production: 22 | adapter: sqlite3 23 | database: db/production.sqlite3 24 | pool: 5 25 | timeout: 5000 26 | -------------------------------------------------------------------------------- /test/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | Dummy::Application.initialize! 6 | -------------------------------------------------------------------------------- /test/dummy/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Log error messages when you accidentally call methods on nil. 10 | config.whiny_nils = true 11 | 12 | # Show full error reports and disable caching 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger 20 | config.active_support.deprecation = :log 21 | 22 | # Only use best-standards-support built into browsers 23 | config.action_dispatch.best_standards_support = :builtin 24 | 25 | # Do not compress assets 26 | config.assets.compress = false 27 | 28 | # Expands the lines which load the assets 29 | config.assets.debug = true 30 | end 31 | -------------------------------------------------------------------------------- /test/dummy/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = false 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = false 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to Rails.root.join("public/assets") 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | # config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Use a different logger for distributed setups 37 | # config.logger = SyslogLogger.new 38 | 39 | # Use a different cache store in production 40 | # config.cache_store = :mem_cache_store 41 | 42 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 43 | # config.action_controller.asset_host = "http://assets.example.com" 44 | 45 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 46 | # config.assets.precompile += %w( search.js ) 47 | 48 | # Disable delivery errors, bad email addresses will be ignored 49 | # config.action_mailer.raise_delivery_errors = false 50 | 51 | # Enable threaded mode 52 | # config.threadsafe! 53 | 54 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 55 | # the I18n.default_locale when a translation can not be found) 56 | config.i18n.fallbacks = true 57 | 58 | # Send deprecation notices to registered listeners 59 | config.active_support.deprecation = :notify 60 | end 61 | -------------------------------------------------------------------------------- /test/dummy/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Configure static asset server for tests with Cache-Control for performance 11 | config.serve_static_assets = true 12 | config.static_cache_control = "public, max-age=3600" 13 | 14 | # Log error messages when you accidentally call methods on nil 15 | config.whiny_nils = true 16 | 17 | # Show full error reports and disable caching 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates 22 | config.action_dispatch.show_exceptions = false 23 | 24 | # Disable request forgery protection in test environment 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | config.action_mailer.delivery_method = :test 31 | 32 | # Use SQL instead of Active Record's schema dumper when creating the test database. 33 | # This is necessary if your schema can't be completely dumped by the schema dumper, 34 | # like if you have constraints or database-specific column types 35 | # config.active_record.schema_format = :sql 36 | 37 | # Print deprecation notices to the stderr 38 | config.active_support.deprecation = :stderr 39 | end 40 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format 4 | # (all these examples are active by default): 5 | # ActiveSupport::Inflector.inflections do |inflect| 6 | # inflect.plural /^(ox)$/i, '\1en' 7 | # inflect.singular /^(ox)en/i, '\1' 8 | # inflect.irregular 'person', 'people' 9 | # inflect.uncountable %w( fish sheep ) 10 | # end 11 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | Dummy::Application.config.secret_token = '770fc7d4cb239b6e3f6399c51932d715eeed2454c2f3a044a3740f5c26a8d521beeb9fe6141a5567f01775a5da3d7dff7cab75d7ba3b034c4a5638ab329bdc44' 8 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Dummy::Application.config.session_store :cookie_store, key: '_dummy_session' 4 | 5 | # Use the database for sessions instead of the cookie-based default, 6 | # which shouldn't be used to store highly confidential information 7 | # (create the session table with "rails generate session_migration") 8 | # Dummy::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # Disable root element in JSON by default. 12 | ActiveSupport.on_load(:active_record) do 13 | self.include_root_in_json = false 14 | end 15 | -------------------------------------------------------------------------------- /test/dummy/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | hello: "Hello world" 6 | -------------------------------------------------------------------------------- /test/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.routes.draw do 2 | # The priority is based upon order of creation: 3 | # first created -> highest priority. 4 | 5 | # Sample of regular route: 6 | # match 'products/:id' => 'catalog#view' 7 | # Keep in mind you can assign values other than :controller and :action 8 | 9 | # Sample of named route: 10 | # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase 11 | # This route can be invoked with purchase_url(:id => product.id) 12 | 13 | # Sample resource route (maps HTTP verbs to controller actions automatically): 14 | # resources :products 15 | 16 | # Sample resource route with options: 17 | # resources :products do 18 | # member do 19 | # get 'short' 20 | # post 'toggle' 21 | # end 22 | # 23 | # collection do 24 | # get 'sold' 25 | # end 26 | # end 27 | 28 | # Sample resource route with sub-resources: 29 | # resources :products do 30 | # resources :comments, :sales 31 | # resource :seller 32 | # end 33 | 34 | # Sample resource route with more complex sub-resources 35 | # resources :products do 36 | # resources :comments 37 | # resources :sales do 38 | # get 'recent', :on => :collection 39 | # end 40 | # end 41 | 42 | # Sample resource route within a namespace: 43 | # namespace :admin do 44 | # # Directs /admin/products/* to Admin::ProductsController 45 | # # (app/controllers/admin/products_controller.rb) 46 | # resources :products 47 | # end 48 | 49 | # You can have the root of your site routed with "root" 50 | # just remember to delete public/index.html. 51 | # root :to => 'welcome#index' 52 | 53 | # See how all your routes lay out with "rake routes" 54 | 55 | # This is a legacy wild controller route that's not recommended for RESTful applications. 56 | # Note: This route will make all actions in every controller accessible via GET requests. 57 | # match ':controller(/:action(/:id(.:format)))' 58 | end 59 | -------------------------------------------------------------------------------- /test/dummy/db/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jwhitley/requirejs-rails/7a05a81d35f862becb859b5a8dd6968fb02da4d1/test/dummy/db/.gitkeep -------------------------------------------------------------------------------- /test/dummy/lib/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jwhitley/requirejs-rails/7a05a81d35f862becb859b5a8dd6968fb02da4d1/test/dummy/lib/assets/.gitkeep -------------------------------------------------------------------------------- /test/dummy/log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jwhitley/requirejs-rails/7a05a81d35f862becb859b5a8dd6968fb02da4d1/test/dummy/log/.gitkeep -------------------------------------------------------------------------------- /test/dummy/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /test/dummy/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /test/dummy/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |

We've been notified about this issue and we'll take a look at it shortly.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /test/dummy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jwhitley/requirejs-rails/7a05a81d35f862becb859b5a8dd6968fb02da4d1/test/dummy/public/favicon.ico -------------------------------------------------------------------------------- /test/dummy/script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /test/requirejs-rails_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | require 'execjs' 4 | require 'pathname' 5 | 6 | class RequirejsRailsTest < ActiveSupport::TestCase 7 | test "truth" do 8 | assert_kind_of Module, Requirejs 9 | assert_kind_of Module, Requirejs::Rails 10 | assert_kind_of Class, Requirejs::Rails::Engine 11 | end 12 | 13 | test "require.js version" do 14 | require_js = Pathname.new(__FILE__+'/../../vendor/assets/javascripts/require.js').cleanpath.read 15 | context = ExecJS.compile(require_js) 16 | assert_equal Requirejs::Rails::LibVersion, context.eval("require.version") 17 | end 18 | 19 | test "CHANGELOG up to date" do 20 | changelog_match = (/^### v#{Requirejs::Rails::Version}/ =~ Pathname.new(__FILE__+'/../../CHANGELOG.md').cleanpath.read) 21 | assert changelog_match, "CHANGELOG has no section for v#{Requirejs::Rails::Version}" 22 | end 23 | end 24 | 25 | class RequirejsRailsConfigTest < ActiveSupport::TestCase 26 | def setup 27 | @cfg = Requirejs::Rails::Config.new(Rails.application) 28 | end 29 | 30 | def asset_allowed?(asset_path) 31 | !!@cfg.logical_path_patterns.find do |logical_path_pattern| 32 | logical_path_pattern.match(asset_path) 33 | end 34 | end 35 | 36 | test "config accepts known loaders" do 37 | @cfg.loader = :almond 38 | assert_equal :almond, @cfg.loader 39 | end 40 | 41 | test "config rejects bad loaders" do 42 | assert_raises Requirejs::ConfigError do 43 | @cfg.loader = :wombat 44 | end 45 | end 46 | 47 | test "matches configured logical assets" do 48 | assert_equal true, asset_allowed?("foo.js") 49 | assert_equal false, asset_allowed?("bar.frobnitz") 50 | @cfg.logical_path_patterns.push(Regexp.new("\\.frobnitz\\z")) 51 | assert_equal true, asset_allowed?("bar.frobnitz") 52 | end 53 | 54 | test "should have a default empty user_config" do 55 | assert_kind_of Hash, @cfg.user_config 56 | end 57 | 58 | test "user_config should reject baseUrl" do 59 | exc = assert_raises Requirejs::ConfigError do 60 | @cfg.user_config = {'baseUrl' => '/frobnitz'} 61 | end 62 | assert_match /baseUrl is not needed/, exc.message 63 | end 64 | 65 | test "run_config should inherit user_config settings" do 66 | @cfg.user_config = {'paths' => {'jquery' => 'lib/jquery-1.7.2.min'}} 67 | refute_nil @cfg.run_config['paths'] 68 | assert_kind_of Hash, @cfg.run_config['paths'] 69 | assert_equal 'lib/jquery-1.7.2.min', @cfg.run_config['paths']['jquery'] 70 | end 71 | 72 | test "run_config should allow settings to be overridden" do 73 | @cfg.run_config['baseUrl'] = 'http://cdn.example.com/assets' 74 | assert_equal 'http://cdn.example.com/assets', @cfg.run_config['baseUrl'] 75 | end 76 | 77 | test "build_config should inherit user_config settings" do 78 | @cfg.user_config = {'paths' => {'jquery' => 'lib/jquery-1.7.2.min'}} 79 | refute_nil @cfg.build_config['paths'] 80 | assert_kind_of Hash, @cfg.build_config['paths'] 81 | assert_equal 'lib/jquery-1.7.2.min', @cfg.build_config['paths']['jquery'] 82 | end 83 | 84 | test "run_config should reject irrelevant settings" do 85 | @cfg.user_config = {'optimize' => 'none'} 86 | assert_nil @cfg.run_config['optimize'] 87 | end 88 | 89 | test "build_config should reject irrelevant settings" do 90 | @cfg.user_config = {'priority' => %w{ foo bar baz }} 91 | assert_nil @cfg.build_config['priority'] 92 | end 93 | 94 | ## Almond tests 95 | test "build_config with almond should accept one module" do 96 | @cfg.loader = :almond 97 | @cfg.user_config = {'modules' => [{'name' => 'foo'}]} 98 | assert_match 'almond', @cfg.build_config['modules'][0]['name'] 99 | end 100 | 101 | test "build_config with almond must reject more than one module" do 102 | @cfg.loader = :almond 103 | @cfg.user_config = {'modules' => [{'name' => 'foo'}, {'name' => 'bar'}]} 104 | exc = assert_raises Requirejs::ConfigError do 105 | @cfg.build_config 106 | end 107 | assert_match /requires exactly one module/, exc.message 108 | end 109 | end 110 | 111 | class RequirejsHelperTest < ActionView::TestCase 112 | def setup 113 | controller.requirejs_included = false 114 | Rails.application.config.requirejs.user_config = {} 115 | Rails.application.config.requirejs.delete(:run_config) 116 | Rails.application.config.requirejs.delete(:build_config) 117 | end 118 | 119 | def with_cdn(protocol_relative = false) 120 | Rails.application.config.requirejs.user_config = { 121 | "paths" => { 122 | "jquery" => "#{ protocol_relative ? '' : 'http:' }//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" 123 | } 124 | } 125 | end 126 | 127 | def wrap(tag) 128 | "#{tag}" 129 | end 130 | 131 | test "requirejs_include_tag" do 132 | render text: wrap(requirejs_include_tag) 133 | 134 | assert_select "script:first-of-type[src=\"/javascripts/require.js\"]", count: 1 135 | assert_select "script:last-of-type", text: "require.config({\"baseUrl\":\"/assets\"});" 136 | end 137 | 138 | test "requirejs_include_tag_with_param" do 139 | render text: wrap(requirejs_include_tag("application")) 140 | 141 | assert_select "script:first-of-type[src=\"/javascripts/require.js\"]", count: 1 142 | end 143 | 144 | test "requirejs_include_tag_with_block" do 145 | result = wrap( 146 | requirejs_include_tag("application") do 147 | {"class" => controller.class.name.demodulize} 148 | end 149 | ) 150 | 151 | render text: result 152 | 153 | assert_select "script:first-of-type[src=\"/javascripts/require.js\"]" \ 154 | "[data-class=\"TestController\"]", count: 1 155 | end 156 | 157 | test "requirejs_include_tag can appear only once" do 158 | assert_raises Requirejs::MultipleIncludeError do 159 | requirejs_include_tag 160 | requirejs_include_tag 161 | end 162 | end 163 | 164 | test "requirejs_include_tag with digestified asset paths" do 165 | begin 166 | Rails.application.config.requirejs.user_config = { 167 | "modules" => [ 168 | {"name" => "foo"} 169 | ] 170 | } 171 | 172 | saved_digest = Rails.application.config.assets.digest 173 | Rails.application.config.assets.digest = true 174 | 175 | render text: wrap(requirejs_include_tag) 176 | 177 | assert_select "script:last-of-type", 178 | text: Regexp.new("\\Arequire\\.config\\({.*\"paths\":{.*\"foo\":\"/javascripts/foo\".*}.*}\\);\\z") 179 | ensure 180 | Rails.application.config.assets.digest = saved_digest 181 | end 182 | end 183 | 184 | test "requirejs_include_tag with CDN asset in paths" do 185 | with_cdn 186 | 187 | render text: wrap(requirejs_include_tag) 188 | 189 | assert_select "script:last-of-type", 190 | text: Regexp.new("\\Arequire\\.config\\({.*\"paths\":{.*\"http://ajax\\..*\".*}.*}\\);\\z") 191 | end 192 | 193 | test "requirejs_include_tag with CDN asset and digestified asset paths" do 194 | begin 195 | with_cdn 196 | 197 | saved_digest = Rails.application.config.assets.digest 198 | Rails.application.config.assets.digest = true 199 | 200 | render text: wrap(requirejs_include_tag) 201 | 202 | assert_select "script:last-of-type", 203 | text: Regexp.new("\\Arequire\\.config\\({.*\"paths\":{.*\"http://ajax\\..*\".*}.*}\\);\\z") 204 | ensure 205 | Rails.application.config.assets.digest = saved_digest 206 | end 207 | end 208 | 209 | test "requirejs_include_tag with protocol relative CDN asset in paths" do 210 | with_cdn(true) 211 | 212 | render text: wrap(requirejs_include_tag) 213 | 214 | assert_select "script:last-of-type", 215 | text: Regexp.new("\\Arequire\\.config\\({.*\"paths\":{.*\"//ajax\\..*\".*}.*}\\);\\z") 216 | end 217 | end 218 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # Configure Rails Environment 2 | ENV["RAILS_ENV"] = "test" 3 | 4 | require File.expand_path("../dummy/config/environment.rb", __FILE__) 5 | require "rails/test_help" 6 | 7 | Rails.backtrace_cleaner.remove_silencers! 8 | 9 | # Load support files 10 | Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } 11 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/almond.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license almond 0.3.3 Copyright jQuery Foundation and other contributors. 3 | * Released under MIT license, http://github.com/requirejs/almond/LICENSE 4 | */ 5 | //Going sloppy to avoid 'use strict' string cost, but strict practices should 6 | //be followed. 7 | /*global setTimeout: false */ 8 | 9 | var requirejs, require, define; 10 | (function (undef) { 11 | var main, req, makeMap, handlers, 12 | defined = {}, 13 | waiting = {}, 14 | config = {}, 15 | defining = {}, 16 | hasOwn = Object.prototype.hasOwnProperty, 17 | aps = [].slice, 18 | jsSuffixRegExp = /\.js$/; 19 | 20 | function hasProp(obj, prop) { 21 | return hasOwn.call(obj, prop); 22 | } 23 | 24 | /** 25 | * Given a relative module name, like ./something, normalize it to 26 | * a real name that can be mapped to a path. 27 | * @param {String} name the relative name 28 | * @param {String} baseName a real name that the name arg is relative 29 | * to. 30 | * @returns {String} normalized name 31 | */ 32 | function normalize(name, baseName) { 33 | var nameParts, nameSegment, mapValue, foundMap, lastIndex, 34 | foundI, foundStarMap, starI, i, j, part, normalizedBaseParts, 35 | baseParts = baseName && baseName.split("/"), 36 | map = config.map, 37 | starMap = (map && map['*']) || {}; 38 | 39 | //Adjust any relative paths. 40 | if (name) { 41 | name = name.split('/'); 42 | lastIndex = name.length - 1; 43 | 44 | // If wanting node ID compatibility, strip .js from end 45 | // of IDs. Have to do this here, and not in nameToUrl 46 | // because node allows either .js or non .js to map 47 | // to same file. 48 | if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { 49 | name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); 50 | } 51 | 52 | // Starts with a '.' so need the baseName 53 | if (name[0].charAt(0) === '.' && baseParts) { 54 | //Convert baseName to array, and lop off the last part, 55 | //so that . matches that 'directory' and not name of the baseName's 56 | //module. For instance, baseName of 'one/two/three', maps to 57 | //'one/two/three.js', but we want the directory, 'one/two' for 58 | //this normalization. 59 | normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); 60 | name = normalizedBaseParts.concat(name); 61 | } 62 | 63 | //start trimDots 64 | for (i = 0; i < name.length; i++) { 65 | part = name[i]; 66 | if (part === '.') { 67 | name.splice(i, 1); 68 | i -= 1; 69 | } else if (part === '..') { 70 | // If at the start, or previous value is still .., 71 | // keep them so that when converted to a path it may 72 | // still work when converted to a path, even though 73 | // as an ID it is less than ideal. In larger point 74 | // releases, may be better to just kick out an error. 75 | if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') { 76 | continue; 77 | } else if (i > 0) { 78 | name.splice(i - 1, 2); 79 | i -= 2; 80 | } 81 | } 82 | } 83 | //end trimDots 84 | 85 | name = name.join('/'); 86 | } 87 | 88 | //Apply map config if available. 89 | if ((baseParts || starMap) && map) { 90 | nameParts = name.split('/'); 91 | 92 | for (i = nameParts.length; i > 0; i -= 1) { 93 | nameSegment = nameParts.slice(0, i).join("/"); 94 | 95 | if (baseParts) { 96 | //Find the longest baseName segment match in the config. 97 | //So, do joins on the biggest to smallest lengths of baseParts. 98 | for (j = baseParts.length; j > 0; j -= 1) { 99 | mapValue = map[baseParts.slice(0, j).join('/')]; 100 | 101 | //baseName segment has config, find if it has one for 102 | //this name. 103 | if (mapValue) { 104 | mapValue = mapValue[nameSegment]; 105 | if (mapValue) { 106 | //Match, update name to the new value. 107 | foundMap = mapValue; 108 | foundI = i; 109 | break; 110 | } 111 | } 112 | } 113 | } 114 | 115 | if (foundMap) { 116 | break; 117 | } 118 | 119 | //Check for a star map match, but just hold on to it, 120 | //if there is a shorter segment match later in a matching 121 | //config, then favor over this star map. 122 | if (!foundStarMap && starMap && starMap[nameSegment]) { 123 | foundStarMap = starMap[nameSegment]; 124 | starI = i; 125 | } 126 | } 127 | 128 | if (!foundMap && foundStarMap) { 129 | foundMap = foundStarMap; 130 | foundI = starI; 131 | } 132 | 133 | if (foundMap) { 134 | nameParts.splice(0, foundI, foundMap); 135 | name = nameParts.join('/'); 136 | } 137 | } 138 | 139 | return name; 140 | } 141 | 142 | function makeRequire(relName, forceSync) { 143 | return function () { 144 | //A version of a require function that passes a moduleName 145 | //value for items that may need to 146 | //look up paths relative to the moduleName 147 | var args = aps.call(arguments, 0); 148 | 149 | //If first arg is not require('string'), and there is only 150 | //one arg, it is the array form without a callback. Insert 151 | //a null so that the following concat is correct. 152 | if (typeof args[0] !== 'string' && args.length === 1) { 153 | args.push(null); 154 | } 155 | return req.apply(undef, args.concat([relName, forceSync])); 156 | }; 157 | } 158 | 159 | function makeNormalize(relName) { 160 | return function (name) { 161 | return normalize(name, relName); 162 | }; 163 | } 164 | 165 | function makeLoad(depName) { 166 | return function (value) { 167 | defined[depName] = value; 168 | }; 169 | } 170 | 171 | function callDep(name) { 172 | if (hasProp(waiting, name)) { 173 | var args = waiting[name]; 174 | delete waiting[name]; 175 | defining[name] = true; 176 | main.apply(undef, args); 177 | } 178 | 179 | if (!hasProp(defined, name) && !hasProp(defining, name)) { 180 | throw new Error('No ' + name); 181 | } 182 | return defined[name]; 183 | } 184 | 185 | //Turns a plugin!resource to [plugin, resource] 186 | //with the plugin being undefined if the name 187 | //did not have a plugin prefix. 188 | function splitPrefix(name) { 189 | var prefix, 190 | index = name ? name.indexOf('!') : -1; 191 | if (index > -1) { 192 | prefix = name.substring(0, index); 193 | name = name.substring(index + 1, name.length); 194 | } 195 | return [prefix, name]; 196 | } 197 | 198 | //Creates a parts array for a relName where first part is plugin ID, 199 | //second part is resource ID. Assumes relName has already been normalized. 200 | function makeRelParts(relName) { 201 | return relName ? splitPrefix(relName) : []; 202 | } 203 | 204 | /** 205 | * Makes a name map, normalizing the name, and using a plugin 206 | * for normalization if necessary. Grabs a ref to plugin 207 | * too, as an optimization. 208 | */ 209 | makeMap = function (name, relParts) { 210 | var plugin, 211 | parts = splitPrefix(name), 212 | prefix = parts[0], 213 | relResourceName = relParts[1]; 214 | 215 | name = parts[1]; 216 | 217 | if (prefix) { 218 | prefix = normalize(prefix, relResourceName); 219 | plugin = callDep(prefix); 220 | } 221 | 222 | //Normalize according 223 | if (prefix) { 224 | if (plugin && plugin.normalize) { 225 | name = plugin.normalize(name, makeNormalize(relResourceName)); 226 | } else { 227 | name = normalize(name, relResourceName); 228 | } 229 | } else { 230 | name = normalize(name, relResourceName); 231 | parts = splitPrefix(name); 232 | prefix = parts[0]; 233 | name = parts[1]; 234 | if (prefix) { 235 | plugin = callDep(prefix); 236 | } 237 | } 238 | 239 | //Using ridiculous property names for space reasons 240 | return { 241 | f: prefix ? prefix + '!' + name : name, //fullName 242 | n: name, 243 | pr: prefix, 244 | p: plugin 245 | }; 246 | }; 247 | 248 | function makeConfig(name) { 249 | return function () { 250 | return (config && config.config && config.config[name]) || {}; 251 | }; 252 | } 253 | 254 | handlers = { 255 | require: function (name) { 256 | return makeRequire(name); 257 | }, 258 | exports: function (name) { 259 | var e = defined[name]; 260 | if (typeof e !== 'undefined') { 261 | return e; 262 | } else { 263 | return (defined[name] = {}); 264 | } 265 | }, 266 | module: function (name) { 267 | return { 268 | id: name, 269 | uri: '', 270 | exports: defined[name], 271 | config: makeConfig(name) 272 | }; 273 | } 274 | }; 275 | 276 | main = function (name, deps, callback, relName) { 277 | var cjsModule, depName, ret, map, i, relParts, 278 | args = [], 279 | callbackType = typeof callback, 280 | usingExports; 281 | 282 | //Use name if no relName 283 | relName = relName || name; 284 | relParts = makeRelParts(relName); 285 | 286 | //Call the callback to define the module, if necessary. 287 | if (callbackType === 'undefined' || callbackType === 'function') { 288 | //Pull out the defined dependencies and pass the ordered 289 | //values to the callback. 290 | //Default to [require, exports, module] if no deps 291 | deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps; 292 | for (i = 0; i < deps.length; i += 1) { 293 | map = makeMap(deps[i], relParts); 294 | depName = map.f; 295 | 296 | //Fast path CommonJS standard dependencies. 297 | if (depName === "require") { 298 | args[i] = handlers.require(name); 299 | } else if (depName === "exports") { 300 | //CommonJS module spec 1.1 301 | args[i] = handlers.exports(name); 302 | usingExports = true; 303 | } else if (depName === "module") { 304 | //CommonJS module spec 1.1 305 | cjsModule = args[i] = handlers.module(name); 306 | } else if (hasProp(defined, depName) || 307 | hasProp(waiting, depName) || 308 | hasProp(defining, depName)) { 309 | args[i] = callDep(depName); 310 | } else if (map.p) { 311 | map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {}); 312 | args[i] = defined[depName]; 313 | } else { 314 | throw new Error(name + ' missing ' + depName); 315 | } 316 | } 317 | 318 | ret = callback ? callback.apply(defined[name], args) : undefined; 319 | 320 | if (name) { 321 | //If setting exports via "module" is in play, 322 | //favor that over return value and exports. After that, 323 | //favor a non-undefined return value over exports use. 324 | if (cjsModule && cjsModule.exports !== undef && 325 | cjsModule.exports !== defined[name]) { 326 | defined[name] = cjsModule.exports; 327 | } else if (ret !== undef || !usingExports) { 328 | //Use the return value from the function. 329 | defined[name] = ret; 330 | } 331 | } 332 | } else if (name) { 333 | //May just be an object definition for the module. Only 334 | //worry about defining if have a module name. 335 | defined[name] = callback; 336 | } 337 | }; 338 | 339 | requirejs = require = req = function (deps, callback, relName, forceSync, alt) { 340 | if (typeof deps === "string") { 341 | if (handlers[deps]) { 342 | //callback in this case is really relName 343 | return handlers[deps](callback); 344 | } 345 | //Just return the module wanted. In this scenario, the 346 | //deps arg is the module name, and second arg (if passed) 347 | //is just the relName. 348 | //Normalize module name, if it contains . or .. 349 | return callDep(makeMap(deps, makeRelParts(callback)).f); 350 | } else if (!deps.splice) { 351 | //deps is a config object, not an array. 352 | config = deps; 353 | if (config.deps) { 354 | req(config.deps, config.callback); 355 | } 356 | if (!callback) { 357 | return; 358 | } 359 | 360 | if (callback.splice) { 361 | //callback is an array, which means it is a dependency list. 362 | //Adjust args if there are dependencies 363 | deps = callback; 364 | callback = relName; 365 | relName = null; 366 | } else { 367 | deps = undef; 368 | } 369 | } 370 | 371 | //Support require(['a']) 372 | callback = callback || function () {}; 373 | 374 | //If relName is a function, it is an errback handler, 375 | //so remove it. 376 | if (typeof relName === 'function') { 377 | relName = forceSync; 378 | forceSync = alt; 379 | } 380 | 381 | //Simulate async callback; 382 | if (forceSync) { 383 | main(undef, deps, callback, relName); 384 | } else { 385 | //Using a non-zero value because of concern for what old browsers 386 | //do, and latest browsers "upgrade" to 4 if lower value is used: 387 | //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout: 388 | //If want a value immediately, use require('id') instead -- something 389 | //that works in almond on the global level, but not guaranteed and 390 | //unlikely to work in other AMD implementations. 391 | setTimeout(function () { 392 | main(undef, deps, callback, relName); 393 | }, 4); 394 | } 395 | 396 | return req; 397 | }; 398 | 399 | /** 400 | * Just drops the config on the floor, but returns req in case 401 | * the config return value is used. 402 | */ 403 | req.config = function (cfg) { 404 | return req(cfg); 405 | }; 406 | 407 | /** 408 | * Expose module registry for debugging and tooling 409 | */ 410 | requirejs._defined = defined; 411 | 412 | define = function (name, deps, callback) { 413 | if (typeof name !== 'string') { 414 | throw new Error('See almond README: incorrect module build, no module name'); 415 | } 416 | 417 | //This module may not have dependencies 418 | if (!deps.splice) { 419 | //deps is not an array, so probably means 420 | //an object literal or factory function for 421 | //the value. Adjust args. 422 | callback = deps; 423 | deps = []; 424 | } 425 | 426 | if (!hasProp(defined, name) && !hasProp(waiting, name)) { 427 | waiting[name] = [name, deps, callback]; 428 | } 429 | }; 430 | 431 | define.amd = { 432 | jQuery: true 433 | }; 434 | }()); 435 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/require.js: -------------------------------------------------------------------------------- 1 | /** vim: et:ts=4:sw=4:sts=4 2 | * @license RequireJS 2.3.5 Copyright jQuery Foundation and other contributors. 3 | * Released under MIT license, https://github.com/requirejs/requirejs/blob/master/LICENSE 4 | */ 5 | //Not using strict: uneven strict support in browsers, #392, and causes 6 | //problems with requirejs.exec()/transpiler plugins that may not be strict. 7 | /*jslint regexp: true, nomen: true, sloppy: true */ 8 | /*global window, navigator, document, importScripts, setTimeout, opera */ 9 | 10 | var requirejs, require, define; 11 | (function (global, setTimeout) { 12 | var req, s, head, baseElement, dataMain, src, 13 | interactiveScript, currentlyAddingScript, mainScript, subPath, 14 | version = '2.3.5', 15 | commentRegExp = /\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/mg, 16 | cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, 17 | jsSuffixRegExp = /\.js$/, 18 | currDirRegExp = /^\.\//, 19 | op = Object.prototype, 20 | ostring = op.toString, 21 | hasOwn = op.hasOwnProperty, 22 | isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document), 23 | isWebWorker = !isBrowser && typeof importScripts !== 'undefined', 24 | //PS3 indicates loaded and complete, but need to wait for complete 25 | //specifically. Sequence is 'loading', 'loaded', execution, 26 | // then 'complete'. The UA check is unfortunate, but not sure how 27 | //to feature test w/o causing perf issues. 28 | readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ? 29 | /^complete$/ : /^(complete|loaded)$/, 30 | defContextName = '_', 31 | //Oh the tragedy, detecting opera. See the usage of isOpera for reason. 32 | isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]', 33 | contexts = {}, 34 | cfg = {}, 35 | globalDefQueue = [], 36 | useInteractive = false; 37 | 38 | //Could match something like ')//comment', do not lose the prefix to comment. 39 | function commentReplace(match, singlePrefix) { 40 | return singlePrefix || ''; 41 | } 42 | 43 | function isFunction(it) { 44 | return ostring.call(it) === '[object Function]'; 45 | } 46 | 47 | function isArray(it) { 48 | return ostring.call(it) === '[object Array]'; 49 | } 50 | 51 | /** 52 | * Helper function for iterating over an array. If the func returns 53 | * a true value, it will break out of the loop. 54 | */ 55 | function each(ary, func) { 56 | if (ary) { 57 | var i; 58 | for (i = 0; i < ary.length; i += 1) { 59 | if (ary[i] && func(ary[i], i, ary)) { 60 | break; 61 | } 62 | } 63 | } 64 | } 65 | 66 | /** 67 | * Helper function for iterating over an array backwards. If the func 68 | * returns a true value, it will break out of the loop. 69 | */ 70 | function eachReverse(ary, func) { 71 | if (ary) { 72 | var i; 73 | for (i = ary.length - 1; i > -1; i -= 1) { 74 | if (ary[i] && func(ary[i], i, ary)) { 75 | break; 76 | } 77 | } 78 | } 79 | } 80 | 81 | function hasProp(obj, prop) { 82 | return hasOwn.call(obj, prop); 83 | } 84 | 85 | function getOwn(obj, prop) { 86 | return hasProp(obj, prop) && obj[prop]; 87 | } 88 | 89 | /** 90 | * Cycles over properties in an object and calls a function for each 91 | * property value. If the function returns a truthy value, then the 92 | * iteration is stopped. 93 | */ 94 | function eachProp(obj, func) { 95 | var prop; 96 | for (prop in obj) { 97 | if (hasProp(obj, prop)) { 98 | if (func(obj[prop], prop)) { 99 | break; 100 | } 101 | } 102 | } 103 | } 104 | 105 | /** 106 | * Simple function to mix in properties from source into target, 107 | * but only if target does not already have a property of the same name. 108 | */ 109 | function mixin(target, source, force, deepStringMixin) { 110 | if (source) { 111 | eachProp(source, function (value, prop) { 112 | if (force || !hasProp(target, prop)) { 113 | if (deepStringMixin && typeof value === 'object' && value && 114 | !isArray(value) && !isFunction(value) && 115 | !(value instanceof RegExp)) { 116 | 117 | if (!target[prop]) { 118 | target[prop] = {}; 119 | } 120 | mixin(target[prop], value, force, deepStringMixin); 121 | } else { 122 | target[prop] = value; 123 | } 124 | } 125 | }); 126 | } 127 | return target; 128 | } 129 | 130 | //Similar to Function.prototype.bind, but the 'this' object is specified 131 | //first, since it is easier to read/figure out what 'this' will be. 132 | function bind(obj, fn) { 133 | return function () { 134 | return fn.apply(obj, arguments); 135 | }; 136 | } 137 | 138 | function scripts() { 139 | return document.getElementsByTagName('script'); 140 | } 141 | 142 | function defaultOnError(err) { 143 | throw err; 144 | } 145 | 146 | //Allow getting a global that is expressed in 147 | //dot notation, like 'a.b.c'. 148 | function getGlobal(value) { 149 | if (!value) { 150 | return value; 151 | } 152 | var g = global; 153 | each(value.split('.'), function (part) { 154 | g = g[part]; 155 | }); 156 | return g; 157 | } 158 | 159 | /** 160 | * Constructs an error with a pointer to an URL with more information. 161 | * @param {String} id the error ID that maps to an ID on a web page. 162 | * @param {String} message human readable error. 163 | * @param {Error} [err] the original error, if there is one. 164 | * 165 | * @returns {Error} 166 | */ 167 | function makeError(id, msg, err, requireModules) { 168 | var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id); 169 | e.requireType = id; 170 | e.requireModules = requireModules; 171 | if (err) { 172 | e.originalError = err; 173 | } 174 | return e; 175 | } 176 | 177 | if (typeof define !== 'undefined') { 178 | //If a define is already in play via another AMD loader, 179 | //do not overwrite. 180 | return; 181 | } 182 | 183 | if (typeof requirejs !== 'undefined') { 184 | if (isFunction(requirejs)) { 185 | //Do not overwrite an existing requirejs instance. 186 | return; 187 | } 188 | cfg = requirejs; 189 | requirejs = undefined; 190 | } 191 | 192 | //Allow for a require config object 193 | if (typeof require !== 'undefined' && !isFunction(require)) { 194 | //assume it is a config object. 195 | cfg = require; 196 | require = undefined; 197 | } 198 | 199 | function newContext(contextName) { 200 | var inCheckLoaded, Module, context, handlers, 201 | checkLoadedTimeoutId, 202 | config = { 203 | //Defaults. Do not set a default for map 204 | //config to speed up normalize(), which 205 | //will run faster if there is no default. 206 | waitSeconds: 7, 207 | baseUrl: './', 208 | paths: {}, 209 | bundles: {}, 210 | pkgs: {}, 211 | shim: {}, 212 | config: {} 213 | }, 214 | registry = {}, 215 | //registry of just enabled modules, to speed 216 | //cycle breaking code when lots of modules 217 | //are registered, but not activated. 218 | enabledRegistry = {}, 219 | undefEvents = {}, 220 | defQueue = [], 221 | defined = {}, 222 | urlFetched = {}, 223 | bundlesMap = {}, 224 | requireCounter = 1, 225 | unnormalizedCounter = 1; 226 | 227 | /** 228 | * Trims the . and .. from an array of path segments. 229 | * It will keep a leading path segment if a .. will become 230 | * the first path segment, to help with module name lookups, 231 | * which act like paths, but can be remapped. But the end result, 232 | * all paths that use this function should look normalized. 233 | * NOTE: this method MODIFIES the input array. 234 | * @param {Array} ary the array of path segments. 235 | */ 236 | function trimDots(ary) { 237 | var i, part; 238 | for (i = 0; i < ary.length; i++) { 239 | part = ary[i]; 240 | if (part === '.') { 241 | ary.splice(i, 1); 242 | i -= 1; 243 | } else if (part === '..') { 244 | // If at the start, or previous value is still .., 245 | // keep them so that when converted to a path it may 246 | // still work when converted to a path, even though 247 | // as an ID it is less than ideal. In larger point 248 | // releases, may be better to just kick out an error. 249 | if (i === 0 || (i === 1 && ary[2] === '..') || ary[i - 1] === '..') { 250 | continue; 251 | } else if (i > 0) { 252 | ary.splice(i - 1, 2); 253 | i -= 2; 254 | } 255 | } 256 | } 257 | } 258 | 259 | /** 260 | * Given a relative module name, like ./something, normalize it to 261 | * a real name that can be mapped to a path. 262 | * @param {String} name the relative name 263 | * @param {String} baseName a real name that the name arg is relative 264 | * to. 265 | * @param {Boolean} applyMap apply the map config to the value. Should 266 | * only be done if this normalization is for a dependency ID. 267 | * @returns {String} normalized name 268 | */ 269 | function normalize(name, baseName, applyMap) { 270 | var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex, 271 | foundMap, foundI, foundStarMap, starI, normalizedBaseParts, 272 | baseParts = (baseName && baseName.split('/')), 273 | map = config.map, 274 | starMap = map && map['*']; 275 | 276 | //Adjust any relative paths. 277 | if (name) { 278 | name = name.split('/'); 279 | lastIndex = name.length - 1; 280 | 281 | // If wanting node ID compatibility, strip .js from end 282 | // of IDs. Have to do this here, and not in nameToUrl 283 | // because node allows either .js or non .js to map 284 | // to same file. 285 | if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { 286 | name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); 287 | } 288 | 289 | // Starts with a '.' so need the baseName 290 | if (name[0].charAt(0) === '.' && baseParts) { 291 | //Convert baseName to array, and lop off the last part, 292 | //so that . matches that 'directory' and not name of the baseName's 293 | //module. For instance, baseName of 'one/two/three', maps to 294 | //'one/two/three.js', but we want the directory, 'one/two' for 295 | //this normalization. 296 | normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); 297 | name = normalizedBaseParts.concat(name); 298 | } 299 | 300 | trimDots(name); 301 | name = name.join('/'); 302 | } 303 | 304 | //Apply map config if available. 305 | if (applyMap && map && (baseParts || starMap)) { 306 | nameParts = name.split('/'); 307 | 308 | outerLoop: for (i = nameParts.length; i > 0; i -= 1) { 309 | nameSegment = nameParts.slice(0, i).join('/'); 310 | 311 | if (baseParts) { 312 | //Find the longest baseName segment match in the config. 313 | //So, do joins on the biggest to smallest lengths of baseParts. 314 | for (j = baseParts.length; j > 0; j -= 1) { 315 | mapValue = getOwn(map, baseParts.slice(0, j).join('/')); 316 | 317 | //baseName segment has config, find if it has one for 318 | //this name. 319 | if (mapValue) { 320 | mapValue = getOwn(mapValue, nameSegment); 321 | if (mapValue) { 322 | //Match, update name to the new value. 323 | foundMap = mapValue; 324 | foundI = i; 325 | break outerLoop; 326 | } 327 | } 328 | } 329 | } 330 | 331 | //Check for a star map match, but just hold on to it, 332 | //if there is a shorter segment match later in a matching 333 | //config, then favor over this star map. 334 | if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) { 335 | foundStarMap = getOwn(starMap, nameSegment); 336 | starI = i; 337 | } 338 | } 339 | 340 | if (!foundMap && foundStarMap) { 341 | foundMap = foundStarMap; 342 | foundI = starI; 343 | } 344 | 345 | if (foundMap) { 346 | nameParts.splice(0, foundI, foundMap); 347 | name = nameParts.join('/'); 348 | } 349 | } 350 | 351 | // If the name points to a package's name, use 352 | // the package main instead. 353 | pkgMain = getOwn(config.pkgs, name); 354 | 355 | return pkgMain ? pkgMain : name; 356 | } 357 | 358 | function removeScript(name) { 359 | if (isBrowser) { 360 | each(scripts(), function (scriptNode) { 361 | if (scriptNode.getAttribute('data-requiremodule') === name && 362 | scriptNode.getAttribute('data-requirecontext') === context.contextName) { 363 | scriptNode.parentNode.removeChild(scriptNode); 364 | return true; 365 | } 366 | }); 367 | } 368 | } 369 | 370 | function hasPathFallback(id) { 371 | var pathConfig = getOwn(config.paths, id); 372 | if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) { 373 | //Pop off the first array value, since it failed, and 374 | //retry 375 | pathConfig.shift(); 376 | context.require.undef(id); 377 | 378 | //Custom require that does not do map translation, since 379 | //ID is "absolute", already mapped/resolved. 380 | context.makeRequire(null, { 381 | skipMap: true 382 | })([id]); 383 | 384 | return true; 385 | } 386 | } 387 | 388 | //Turns a plugin!resource to [plugin, resource] 389 | //with the plugin being undefined if the name 390 | //did not have a plugin prefix. 391 | function splitPrefix(name) { 392 | var prefix, 393 | index = name ? name.indexOf('!') : -1; 394 | if (index > -1) { 395 | prefix = name.substring(0, index); 396 | name = name.substring(index + 1, name.length); 397 | } 398 | return [prefix, name]; 399 | } 400 | 401 | /** 402 | * Creates a module mapping that includes plugin prefix, module 403 | * name, and path. If parentModuleMap is provided it will 404 | * also normalize the name via require.normalize() 405 | * 406 | * @param {String} name the module name 407 | * @param {String} [parentModuleMap] parent module map 408 | * for the module name, used to resolve relative names. 409 | * @param {Boolean} isNormalized: is the ID already normalized. 410 | * This is true if this call is done for a define() module ID. 411 | * @param {Boolean} applyMap: apply the map config to the ID. 412 | * Should only be true if this map is for a dependency. 413 | * 414 | * @returns {Object} 415 | */ 416 | function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) { 417 | var url, pluginModule, suffix, nameParts, 418 | prefix = null, 419 | parentName = parentModuleMap ? parentModuleMap.name : null, 420 | originalName = name, 421 | isDefine = true, 422 | normalizedName = ''; 423 | 424 | //If no name, then it means it is a require call, generate an 425 | //internal name. 426 | if (!name) { 427 | isDefine = false; 428 | name = '_@r' + (requireCounter += 1); 429 | } 430 | 431 | nameParts = splitPrefix(name); 432 | prefix = nameParts[0]; 433 | name = nameParts[1]; 434 | 435 | if (prefix) { 436 | prefix = normalize(prefix, parentName, applyMap); 437 | pluginModule = getOwn(defined, prefix); 438 | } 439 | 440 | //Account for relative paths if there is a base name. 441 | if (name) { 442 | if (prefix) { 443 | if (isNormalized) { 444 | normalizedName = name; 445 | } else if (pluginModule && pluginModule.normalize) { 446 | //Plugin is loaded, use its normalize method. 447 | normalizedName = pluginModule.normalize(name, function (name) { 448 | return normalize(name, parentName, applyMap); 449 | }); 450 | } else { 451 | // If nested plugin references, then do not try to 452 | // normalize, as it will not normalize correctly. This 453 | // places a restriction on resourceIds, and the longer 454 | // term solution is not to normalize until plugins are 455 | // loaded and all normalizations to allow for async 456 | // loading of a loader plugin. But for now, fixes the 457 | // common uses. Details in #1131 458 | normalizedName = name.indexOf('!') === -1 ? 459 | normalize(name, parentName, applyMap) : 460 | name; 461 | } 462 | } else { 463 | //A regular module. 464 | normalizedName = normalize(name, parentName, applyMap); 465 | 466 | //Normalized name may be a plugin ID due to map config 467 | //application in normalize. The map config values must 468 | //already be normalized, so do not need to redo that part. 469 | nameParts = splitPrefix(normalizedName); 470 | prefix = nameParts[0]; 471 | normalizedName = nameParts[1]; 472 | isNormalized = true; 473 | 474 | url = context.nameToUrl(normalizedName); 475 | } 476 | } 477 | 478 | //If the id is a plugin id that cannot be determined if it needs 479 | //normalization, stamp it with a unique ID so two matching relative 480 | //ids that may conflict can be separate. 481 | suffix = prefix && !pluginModule && !isNormalized ? 482 | '_unnormalized' + (unnormalizedCounter += 1) : 483 | ''; 484 | 485 | return { 486 | prefix: prefix, 487 | name: normalizedName, 488 | parentMap: parentModuleMap, 489 | unnormalized: !!suffix, 490 | url: url, 491 | originalName: originalName, 492 | isDefine: isDefine, 493 | id: (prefix ? 494 | prefix + '!' + normalizedName : 495 | normalizedName) + suffix 496 | }; 497 | } 498 | 499 | function getModule(depMap) { 500 | var id = depMap.id, 501 | mod = getOwn(registry, id); 502 | 503 | if (!mod) { 504 | mod = registry[id] = new context.Module(depMap); 505 | } 506 | 507 | return mod; 508 | } 509 | 510 | function on(depMap, name, fn) { 511 | var id = depMap.id, 512 | mod = getOwn(registry, id); 513 | 514 | if (hasProp(defined, id) && 515 | (!mod || mod.defineEmitComplete)) { 516 | if (name === 'defined') { 517 | fn(defined[id]); 518 | } 519 | } else { 520 | mod = getModule(depMap); 521 | if (mod.error && name === 'error') { 522 | fn(mod.error); 523 | } else { 524 | mod.on(name, fn); 525 | } 526 | } 527 | } 528 | 529 | function onError(err, errback) { 530 | var ids = err.requireModules, 531 | notified = false; 532 | 533 | if (errback) { 534 | errback(err); 535 | } else { 536 | each(ids, function (id) { 537 | var mod = getOwn(registry, id); 538 | if (mod) { 539 | //Set error on module, so it skips timeout checks. 540 | mod.error = err; 541 | if (mod.events.error) { 542 | notified = true; 543 | mod.emit('error', err); 544 | } 545 | } 546 | }); 547 | 548 | if (!notified) { 549 | req.onError(err); 550 | } 551 | } 552 | } 553 | 554 | /** 555 | * Internal method to transfer globalQueue items to this context's 556 | * defQueue. 557 | */ 558 | function takeGlobalQueue() { 559 | //Push all the globalDefQueue items into the context's defQueue 560 | if (globalDefQueue.length) { 561 | each(globalDefQueue, function(queueItem) { 562 | var id = queueItem[0]; 563 | if (typeof id === 'string') { 564 | context.defQueueMap[id] = true; 565 | } 566 | defQueue.push(queueItem); 567 | }); 568 | globalDefQueue = []; 569 | } 570 | } 571 | 572 | handlers = { 573 | 'require': function (mod) { 574 | if (mod.require) { 575 | return mod.require; 576 | } else { 577 | return (mod.require = context.makeRequire(mod.map)); 578 | } 579 | }, 580 | 'exports': function (mod) { 581 | mod.usingExports = true; 582 | if (mod.map.isDefine) { 583 | if (mod.exports) { 584 | return (defined[mod.map.id] = mod.exports); 585 | } else { 586 | return (mod.exports = defined[mod.map.id] = {}); 587 | } 588 | } 589 | }, 590 | 'module': function (mod) { 591 | if (mod.module) { 592 | return mod.module; 593 | } else { 594 | return (mod.module = { 595 | id: mod.map.id, 596 | uri: mod.map.url, 597 | config: function () { 598 | return getOwn(config.config, mod.map.id) || {}; 599 | }, 600 | exports: mod.exports || (mod.exports = {}) 601 | }); 602 | } 603 | } 604 | }; 605 | 606 | function cleanRegistry(id) { 607 | //Clean up machinery used for waiting modules. 608 | delete registry[id]; 609 | delete enabledRegistry[id]; 610 | } 611 | 612 | function breakCycle(mod, traced, processed) { 613 | var id = mod.map.id; 614 | 615 | if (mod.error) { 616 | mod.emit('error', mod.error); 617 | } else { 618 | traced[id] = true; 619 | each(mod.depMaps, function (depMap, i) { 620 | var depId = depMap.id, 621 | dep = getOwn(registry, depId); 622 | 623 | //Only force things that have not completed 624 | //being defined, so still in the registry, 625 | //and only if it has not been matched up 626 | //in the module already. 627 | if (dep && !mod.depMatched[i] && !processed[depId]) { 628 | if (getOwn(traced, depId)) { 629 | mod.defineDep(i, defined[depId]); 630 | mod.check(); //pass false? 631 | } else { 632 | breakCycle(dep, traced, processed); 633 | } 634 | } 635 | }); 636 | processed[id] = true; 637 | } 638 | } 639 | 640 | function checkLoaded() { 641 | var err, usingPathFallback, 642 | waitInterval = config.waitSeconds * 1000, 643 | //It is possible to disable the wait interval by using waitSeconds of 0. 644 | expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), 645 | noLoads = [], 646 | reqCalls = [], 647 | stillLoading = false, 648 | needCycleCheck = true; 649 | 650 | //Do not bother if this call was a result of a cycle break. 651 | if (inCheckLoaded) { 652 | return; 653 | } 654 | 655 | inCheckLoaded = true; 656 | 657 | //Figure out the state of all the modules. 658 | eachProp(enabledRegistry, function (mod) { 659 | var map = mod.map, 660 | modId = map.id; 661 | 662 | //Skip things that are not enabled or in error state. 663 | if (!mod.enabled) { 664 | return; 665 | } 666 | 667 | if (!map.isDefine) { 668 | reqCalls.push(mod); 669 | } 670 | 671 | if (!mod.error) { 672 | //If the module should be executed, and it has not 673 | //been inited and time is up, remember it. 674 | if (!mod.inited && expired) { 675 | if (hasPathFallback(modId)) { 676 | usingPathFallback = true; 677 | stillLoading = true; 678 | } else { 679 | noLoads.push(modId); 680 | removeScript(modId); 681 | } 682 | } else if (!mod.inited && mod.fetched && map.isDefine) { 683 | stillLoading = true; 684 | if (!map.prefix) { 685 | //No reason to keep looking for unfinished 686 | //loading. If the only stillLoading is a 687 | //plugin resource though, keep going, 688 | //because it may be that a plugin resource 689 | //is waiting on a non-plugin cycle. 690 | return (needCycleCheck = false); 691 | } 692 | } 693 | } 694 | }); 695 | 696 | if (expired && noLoads.length) { 697 | //If wait time expired, throw error of unloaded modules. 698 | err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads); 699 | err.contextName = context.contextName; 700 | return onError(err); 701 | } 702 | 703 | //Not expired, check for a cycle. 704 | if (needCycleCheck) { 705 | each(reqCalls, function (mod) { 706 | breakCycle(mod, {}, {}); 707 | }); 708 | } 709 | 710 | //If still waiting on loads, and the waiting load is something 711 | //other than a plugin resource, or there are still outstanding 712 | //scripts, then just try back later. 713 | if ((!expired || usingPathFallback) && stillLoading) { 714 | //Something is still waiting to load. Wait for it, but only 715 | //if a timeout is not already in effect. 716 | if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) { 717 | checkLoadedTimeoutId = setTimeout(function () { 718 | checkLoadedTimeoutId = 0; 719 | checkLoaded(); 720 | }, 50); 721 | } 722 | } 723 | 724 | inCheckLoaded = false; 725 | } 726 | 727 | Module = function (map) { 728 | this.events = getOwn(undefEvents, map.id) || {}; 729 | this.map = map; 730 | this.shim = getOwn(config.shim, map.id); 731 | this.depExports = []; 732 | this.depMaps = []; 733 | this.depMatched = []; 734 | this.pluginMaps = {}; 735 | this.depCount = 0; 736 | 737 | /* this.exports this.factory 738 | this.depMaps = [], 739 | this.enabled, this.fetched 740 | */ 741 | }; 742 | 743 | Module.prototype = { 744 | init: function (depMaps, factory, errback, options) { 745 | options = options || {}; 746 | 747 | //Do not do more inits if already done. Can happen if there 748 | //are multiple define calls for the same module. That is not 749 | //a normal, common case, but it is also not unexpected. 750 | if (this.inited) { 751 | return; 752 | } 753 | 754 | this.factory = factory; 755 | 756 | if (errback) { 757 | //Register for errors on this module. 758 | this.on('error', errback); 759 | } else if (this.events.error) { 760 | //If no errback already, but there are error listeners 761 | //on this module, set up an errback to pass to the deps. 762 | errback = bind(this, function (err) { 763 | this.emit('error', err); 764 | }); 765 | } 766 | 767 | //Do a copy of the dependency array, so that 768 | //source inputs are not modified. For example 769 | //"shim" deps are passed in here directly, and 770 | //doing a direct modification of the depMaps array 771 | //would affect that config. 772 | this.depMaps = depMaps && depMaps.slice(0); 773 | 774 | this.errback = errback; 775 | 776 | //Indicate this module has be initialized 777 | this.inited = true; 778 | 779 | this.ignore = options.ignore; 780 | 781 | //Could have option to init this module in enabled mode, 782 | //or could have been previously marked as enabled. However, 783 | //the dependencies are not known until init is called. So 784 | //if enabled previously, now trigger dependencies as enabled. 785 | if (options.enabled || this.enabled) { 786 | //Enable this module and dependencies. 787 | //Will call this.check() 788 | this.enable(); 789 | } else { 790 | this.check(); 791 | } 792 | }, 793 | 794 | defineDep: function (i, depExports) { 795 | //Because of cycles, defined callback for a given 796 | //export can be called more than once. 797 | if (!this.depMatched[i]) { 798 | this.depMatched[i] = true; 799 | this.depCount -= 1; 800 | this.depExports[i] = depExports; 801 | } 802 | }, 803 | 804 | fetch: function () { 805 | if (this.fetched) { 806 | return; 807 | } 808 | this.fetched = true; 809 | 810 | context.startTime = (new Date()).getTime(); 811 | 812 | var map = this.map; 813 | 814 | //If the manager is for a plugin managed resource, 815 | //ask the plugin to load it now. 816 | if (this.shim) { 817 | context.makeRequire(this.map, { 818 | enableBuildCallback: true 819 | })(this.shim.deps || [], bind(this, function () { 820 | return map.prefix ? this.callPlugin() : this.load(); 821 | })); 822 | } else { 823 | //Regular dependency. 824 | return map.prefix ? this.callPlugin() : this.load(); 825 | } 826 | }, 827 | 828 | load: function () { 829 | var url = this.map.url; 830 | 831 | //Regular dependency. 832 | if (!urlFetched[url]) { 833 | urlFetched[url] = true; 834 | context.load(this.map.id, url); 835 | } 836 | }, 837 | 838 | /** 839 | * Checks if the module is ready to define itself, and if so, 840 | * define it. 841 | */ 842 | check: function () { 843 | if (!this.enabled || this.enabling) { 844 | return; 845 | } 846 | 847 | var err, cjsModule, 848 | id = this.map.id, 849 | depExports = this.depExports, 850 | exports = this.exports, 851 | factory = this.factory; 852 | 853 | if (!this.inited) { 854 | // Only fetch if not already in the defQueue. 855 | if (!hasProp(context.defQueueMap, id)) { 856 | this.fetch(); 857 | } 858 | } else if (this.error) { 859 | this.emit('error', this.error); 860 | } else if (!this.defining) { 861 | //The factory could trigger another require call 862 | //that would result in checking this module to 863 | //define itself again. If already in the process 864 | //of doing that, skip this work. 865 | this.defining = true; 866 | 867 | if (this.depCount < 1 && !this.defined) { 868 | if (isFunction(factory)) { 869 | //If there is an error listener, favor passing 870 | //to that instead of throwing an error. However, 871 | //only do it for define()'d modules. require 872 | //errbacks should not be called for failures in 873 | //their callbacks (#699). However if a global 874 | //onError is set, use that. 875 | if ((this.events.error && this.map.isDefine) || 876 | req.onError !== defaultOnError) { 877 | try { 878 | exports = context.execCb(id, factory, depExports, exports); 879 | } catch (e) { 880 | err = e; 881 | } 882 | } else { 883 | exports = context.execCb(id, factory, depExports, exports); 884 | } 885 | 886 | // Favor return value over exports. If node/cjs in play, 887 | // then will not have a return value anyway. Favor 888 | // module.exports assignment over exports object. 889 | if (this.map.isDefine && exports === undefined) { 890 | cjsModule = this.module; 891 | if (cjsModule) { 892 | exports = cjsModule.exports; 893 | } else if (this.usingExports) { 894 | //exports already set the defined value. 895 | exports = this.exports; 896 | } 897 | } 898 | 899 | if (err) { 900 | err.requireMap = this.map; 901 | err.requireModules = this.map.isDefine ? [this.map.id] : null; 902 | err.requireType = this.map.isDefine ? 'define' : 'require'; 903 | return onError((this.error = err)); 904 | } 905 | 906 | } else { 907 | //Just a literal value 908 | exports = factory; 909 | } 910 | 911 | this.exports = exports; 912 | 913 | if (this.map.isDefine && !this.ignore) { 914 | defined[id] = exports; 915 | 916 | if (req.onResourceLoad) { 917 | var resLoadMaps = []; 918 | each(this.depMaps, function (depMap) { 919 | resLoadMaps.push(depMap.normalizedMap || depMap); 920 | }); 921 | req.onResourceLoad(context, this.map, resLoadMaps); 922 | } 923 | } 924 | 925 | //Clean up 926 | cleanRegistry(id); 927 | 928 | this.defined = true; 929 | } 930 | 931 | //Finished the define stage. Allow calling check again 932 | //to allow define notifications below in the case of a 933 | //cycle. 934 | this.defining = false; 935 | 936 | if (this.defined && !this.defineEmitted) { 937 | this.defineEmitted = true; 938 | this.emit('defined', this.exports); 939 | this.defineEmitComplete = true; 940 | } 941 | 942 | } 943 | }, 944 | 945 | callPlugin: function () { 946 | var map = this.map, 947 | id = map.id, 948 | //Map already normalized the prefix. 949 | pluginMap = makeModuleMap(map.prefix); 950 | 951 | //Mark this as a dependency for this plugin, so it 952 | //can be traced for cycles. 953 | this.depMaps.push(pluginMap); 954 | 955 | on(pluginMap, 'defined', bind(this, function (plugin) { 956 | var load, normalizedMap, normalizedMod, 957 | bundleId = getOwn(bundlesMap, this.map.id), 958 | name = this.map.name, 959 | parentName = this.map.parentMap ? this.map.parentMap.name : null, 960 | localRequire = context.makeRequire(map.parentMap, { 961 | enableBuildCallback: true 962 | }); 963 | 964 | //If current map is not normalized, wait for that 965 | //normalized name to load instead of continuing. 966 | if (this.map.unnormalized) { 967 | //Normalize the ID if the plugin allows it. 968 | if (plugin.normalize) { 969 | name = plugin.normalize(name, function (name) { 970 | return normalize(name, parentName, true); 971 | }) || ''; 972 | } 973 | 974 | //prefix and name should already be normalized, no need 975 | //for applying map config again either. 976 | normalizedMap = makeModuleMap(map.prefix + '!' + name, 977 | this.map.parentMap, 978 | true); 979 | on(normalizedMap, 980 | 'defined', bind(this, function (value) { 981 | this.map.normalizedMap = normalizedMap; 982 | this.init([], function () { return value; }, null, { 983 | enabled: true, 984 | ignore: true 985 | }); 986 | })); 987 | 988 | normalizedMod = getOwn(registry, normalizedMap.id); 989 | if (normalizedMod) { 990 | //Mark this as a dependency for this plugin, so it 991 | //can be traced for cycles. 992 | this.depMaps.push(normalizedMap); 993 | 994 | if (this.events.error) { 995 | normalizedMod.on('error', bind(this, function (err) { 996 | this.emit('error', err); 997 | })); 998 | } 999 | normalizedMod.enable(); 1000 | } 1001 | 1002 | return; 1003 | } 1004 | 1005 | //If a paths config, then just load that file instead to 1006 | //resolve the plugin, as it is built into that paths layer. 1007 | if (bundleId) { 1008 | this.map.url = context.nameToUrl(bundleId); 1009 | this.load(); 1010 | return; 1011 | } 1012 | 1013 | load = bind(this, function (value) { 1014 | this.init([], function () { return value; }, null, { 1015 | enabled: true 1016 | }); 1017 | }); 1018 | 1019 | load.error = bind(this, function (err) { 1020 | this.inited = true; 1021 | this.error = err; 1022 | err.requireModules = [id]; 1023 | 1024 | //Remove temp unnormalized modules for this module, 1025 | //since they will never be resolved otherwise now. 1026 | eachProp(registry, function (mod) { 1027 | if (mod.map.id.indexOf(id + '_unnormalized') === 0) { 1028 | cleanRegistry(mod.map.id); 1029 | } 1030 | }); 1031 | 1032 | onError(err); 1033 | }); 1034 | 1035 | //Allow plugins to load other code without having to know the 1036 | //context or how to 'complete' the load. 1037 | load.fromText = bind(this, function (text, textAlt) { 1038 | /*jslint evil: true */ 1039 | var moduleName = map.name, 1040 | moduleMap = makeModuleMap(moduleName), 1041 | hasInteractive = useInteractive; 1042 | 1043 | //As of 2.1.0, support just passing the text, to reinforce 1044 | //fromText only being called once per resource. Still 1045 | //support old style of passing moduleName but discard 1046 | //that moduleName in favor of the internal ref. 1047 | if (textAlt) { 1048 | text = textAlt; 1049 | } 1050 | 1051 | //Turn off interactive script matching for IE for any define 1052 | //calls in the text, then turn it back on at the end. 1053 | if (hasInteractive) { 1054 | useInteractive = false; 1055 | } 1056 | 1057 | //Prime the system by creating a module instance for 1058 | //it. 1059 | getModule(moduleMap); 1060 | 1061 | //Transfer any config to this other module. 1062 | if (hasProp(config.config, id)) { 1063 | config.config[moduleName] = config.config[id]; 1064 | } 1065 | 1066 | try { 1067 | req.exec(text); 1068 | } catch (e) { 1069 | return onError(makeError('fromtexteval', 1070 | 'fromText eval for ' + id + 1071 | ' failed: ' + e, 1072 | e, 1073 | [id])); 1074 | } 1075 | 1076 | if (hasInteractive) { 1077 | useInteractive = true; 1078 | } 1079 | 1080 | //Mark this as a dependency for the plugin 1081 | //resource 1082 | this.depMaps.push(moduleMap); 1083 | 1084 | //Support anonymous modules. 1085 | context.completeLoad(moduleName); 1086 | 1087 | //Bind the value of that module to the value for this 1088 | //resource ID. 1089 | localRequire([moduleName], load); 1090 | }); 1091 | 1092 | //Use parentName here since the plugin's name is not reliable, 1093 | //could be some weird string with no path that actually wants to 1094 | //reference the parentName's path. 1095 | plugin.load(map.name, localRequire, load, config); 1096 | })); 1097 | 1098 | context.enable(pluginMap, this); 1099 | this.pluginMaps[pluginMap.id] = pluginMap; 1100 | }, 1101 | 1102 | enable: function () { 1103 | enabledRegistry[this.map.id] = this; 1104 | this.enabled = true; 1105 | 1106 | //Set flag mentioning that the module is enabling, 1107 | //so that immediate calls to the defined callbacks 1108 | //for dependencies do not trigger inadvertent load 1109 | //with the depCount still being zero. 1110 | this.enabling = true; 1111 | 1112 | //Enable each dependency 1113 | each(this.depMaps, bind(this, function (depMap, i) { 1114 | var id, mod, handler; 1115 | 1116 | if (typeof depMap === 'string') { 1117 | //Dependency needs to be converted to a depMap 1118 | //and wired up to this module. 1119 | depMap = makeModuleMap(depMap, 1120 | (this.map.isDefine ? this.map : this.map.parentMap), 1121 | false, 1122 | !this.skipMap); 1123 | this.depMaps[i] = depMap; 1124 | 1125 | handler = getOwn(handlers, depMap.id); 1126 | 1127 | if (handler) { 1128 | this.depExports[i] = handler(this); 1129 | return; 1130 | } 1131 | 1132 | this.depCount += 1; 1133 | 1134 | on(depMap, 'defined', bind(this, function (depExports) { 1135 | if (this.undefed) { 1136 | return; 1137 | } 1138 | this.defineDep(i, depExports); 1139 | this.check(); 1140 | })); 1141 | 1142 | if (this.errback) { 1143 | on(depMap, 'error', bind(this, this.errback)); 1144 | } else if (this.events.error) { 1145 | // No direct errback on this module, but something 1146 | // else is listening for errors, so be sure to 1147 | // propagate the error correctly. 1148 | on(depMap, 'error', bind(this, function(err) { 1149 | this.emit('error', err); 1150 | })); 1151 | } 1152 | } 1153 | 1154 | id = depMap.id; 1155 | mod = registry[id]; 1156 | 1157 | //Skip special modules like 'require', 'exports', 'module' 1158 | //Also, don't call enable if it is already enabled, 1159 | //important in circular dependency cases. 1160 | if (!hasProp(handlers, id) && mod && !mod.enabled) { 1161 | context.enable(depMap, this); 1162 | } 1163 | })); 1164 | 1165 | //Enable each plugin that is used in 1166 | //a dependency 1167 | eachProp(this.pluginMaps, bind(this, function (pluginMap) { 1168 | var mod = getOwn(registry, pluginMap.id); 1169 | if (mod && !mod.enabled) { 1170 | context.enable(pluginMap, this); 1171 | } 1172 | })); 1173 | 1174 | this.enabling = false; 1175 | 1176 | this.check(); 1177 | }, 1178 | 1179 | on: function (name, cb) { 1180 | var cbs = this.events[name]; 1181 | if (!cbs) { 1182 | cbs = this.events[name] = []; 1183 | } 1184 | cbs.push(cb); 1185 | }, 1186 | 1187 | emit: function (name, evt) { 1188 | each(this.events[name], function (cb) { 1189 | cb(evt); 1190 | }); 1191 | if (name === 'error') { 1192 | //Now that the error handler was triggered, remove 1193 | //the listeners, since this broken Module instance 1194 | //can stay around for a while in the registry. 1195 | delete this.events[name]; 1196 | } 1197 | } 1198 | }; 1199 | 1200 | function callGetModule(args) { 1201 | //Skip modules already defined. 1202 | if (!hasProp(defined, args[0])) { 1203 | getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]); 1204 | } 1205 | } 1206 | 1207 | function removeListener(node, func, name, ieName) { 1208 | //Favor detachEvent because of IE9 1209 | //issue, see attachEvent/addEventListener comment elsewhere 1210 | //in this file. 1211 | if (node.detachEvent && !isOpera) { 1212 | //Probably IE. If not it will throw an error, which will be 1213 | //useful to know. 1214 | if (ieName) { 1215 | node.detachEvent(ieName, func); 1216 | } 1217 | } else { 1218 | node.removeEventListener(name, func, false); 1219 | } 1220 | } 1221 | 1222 | /** 1223 | * Given an event from a script node, get the requirejs info from it, 1224 | * and then removes the event listeners on the node. 1225 | * @param {Event} evt 1226 | * @returns {Object} 1227 | */ 1228 | function getScriptData(evt) { 1229 | //Using currentTarget instead of target for Firefox 2.0's sake. Not 1230 | //all old browsers will be supported, but this one was easy enough 1231 | //to support and still makes sense. 1232 | var node = evt.currentTarget || evt.srcElement; 1233 | 1234 | //Remove the listeners once here. 1235 | removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange'); 1236 | removeListener(node, context.onScriptError, 'error'); 1237 | 1238 | return { 1239 | node: node, 1240 | id: node && node.getAttribute('data-requiremodule') 1241 | }; 1242 | } 1243 | 1244 | function intakeDefines() { 1245 | var args; 1246 | 1247 | //Any defined modules in the global queue, intake them now. 1248 | takeGlobalQueue(); 1249 | 1250 | //Make sure any remaining defQueue items get properly processed. 1251 | while (defQueue.length) { 1252 | args = defQueue.shift(); 1253 | if (args[0] === null) { 1254 | return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + 1255 | args[args.length - 1])); 1256 | } else { 1257 | //args are id, deps, factory. Should be normalized by the 1258 | //define() function. 1259 | callGetModule(args); 1260 | } 1261 | } 1262 | context.defQueueMap = {}; 1263 | } 1264 | 1265 | context = { 1266 | config: config, 1267 | contextName: contextName, 1268 | registry: registry, 1269 | defined: defined, 1270 | urlFetched: urlFetched, 1271 | defQueue: defQueue, 1272 | defQueueMap: {}, 1273 | Module: Module, 1274 | makeModuleMap: makeModuleMap, 1275 | nextTick: req.nextTick, 1276 | onError: onError, 1277 | 1278 | /** 1279 | * Set a configuration for the context. 1280 | * @param {Object} cfg config object to integrate. 1281 | */ 1282 | configure: function (cfg) { 1283 | //Make sure the baseUrl ends in a slash. 1284 | if (cfg.baseUrl) { 1285 | if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') { 1286 | cfg.baseUrl += '/'; 1287 | } 1288 | } 1289 | 1290 | // Convert old style urlArgs string to a function. 1291 | if (typeof cfg.urlArgs === 'string') { 1292 | var urlArgs = cfg.urlArgs; 1293 | cfg.urlArgs = function(id, url) { 1294 | return (url.indexOf('?') === -1 ? '?' : '&') + urlArgs; 1295 | }; 1296 | } 1297 | 1298 | //Save off the paths since they require special processing, 1299 | //they are additive. 1300 | var shim = config.shim, 1301 | objs = { 1302 | paths: true, 1303 | bundles: true, 1304 | config: true, 1305 | map: true 1306 | }; 1307 | 1308 | eachProp(cfg, function (value, prop) { 1309 | if (objs[prop]) { 1310 | if (!config[prop]) { 1311 | config[prop] = {}; 1312 | } 1313 | mixin(config[prop], value, true, true); 1314 | } else { 1315 | config[prop] = value; 1316 | } 1317 | }); 1318 | 1319 | //Reverse map the bundles 1320 | if (cfg.bundles) { 1321 | eachProp(cfg.bundles, function (value, prop) { 1322 | each(value, function (v) { 1323 | if (v !== prop) { 1324 | bundlesMap[v] = prop; 1325 | } 1326 | }); 1327 | }); 1328 | } 1329 | 1330 | //Merge shim 1331 | if (cfg.shim) { 1332 | eachProp(cfg.shim, function (value, id) { 1333 | //Normalize the structure 1334 | if (isArray(value)) { 1335 | value = { 1336 | deps: value 1337 | }; 1338 | } 1339 | if ((value.exports || value.init) && !value.exportsFn) { 1340 | value.exportsFn = context.makeShimExports(value); 1341 | } 1342 | shim[id] = value; 1343 | }); 1344 | config.shim = shim; 1345 | } 1346 | 1347 | //Adjust packages if necessary. 1348 | if (cfg.packages) { 1349 | each(cfg.packages, function (pkgObj) { 1350 | var location, name; 1351 | 1352 | pkgObj = typeof pkgObj === 'string' ? {name: pkgObj} : pkgObj; 1353 | 1354 | name = pkgObj.name; 1355 | location = pkgObj.location; 1356 | if (location) { 1357 | config.paths[name] = pkgObj.location; 1358 | } 1359 | 1360 | //Save pointer to main module ID for pkg name. 1361 | //Remove leading dot in main, so main paths are normalized, 1362 | //and remove any trailing .js, since different package 1363 | //envs have different conventions: some use a module name, 1364 | //some use a file name. 1365 | config.pkgs[name] = pkgObj.name + '/' + (pkgObj.main || 'main') 1366 | .replace(currDirRegExp, '') 1367 | .replace(jsSuffixRegExp, ''); 1368 | }); 1369 | } 1370 | 1371 | //If there are any "waiting to execute" modules in the registry, 1372 | //update the maps for them, since their info, like URLs to load, 1373 | //may have changed. 1374 | eachProp(registry, function (mod, id) { 1375 | //If module already has init called, since it is too 1376 | //late to modify them, and ignore unnormalized ones 1377 | //since they are transient. 1378 | if (!mod.inited && !mod.map.unnormalized) { 1379 | mod.map = makeModuleMap(id, null, true); 1380 | } 1381 | }); 1382 | 1383 | //If a deps array or a config callback is specified, then call 1384 | //require with those args. This is useful when require is defined as a 1385 | //config object before require.js is loaded. 1386 | if (cfg.deps || cfg.callback) { 1387 | context.require(cfg.deps || [], cfg.callback); 1388 | } 1389 | }, 1390 | 1391 | makeShimExports: function (value) { 1392 | function fn() { 1393 | var ret; 1394 | if (value.init) { 1395 | ret = value.init.apply(global, arguments); 1396 | } 1397 | return ret || (value.exports && getGlobal(value.exports)); 1398 | } 1399 | return fn; 1400 | }, 1401 | 1402 | makeRequire: function (relMap, options) { 1403 | options = options || {}; 1404 | 1405 | function localRequire(deps, callback, errback) { 1406 | var id, map, requireMod; 1407 | 1408 | if (options.enableBuildCallback && callback && isFunction(callback)) { 1409 | callback.__requireJsBuild = true; 1410 | } 1411 | 1412 | if (typeof deps === 'string') { 1413 | if (isFunction(callback)) { 1414 | //Invalid call 1415 | return onError(makeError('requireargs', 'Invalid require call'), errback); 1416 | } 1417 | 1418 | //If require|exports|module are requested, get the 1419 | //value for them from the special handlers. Caveat: 1420 | //this only works while module is being defined. 1421 | if (relMap && hasProp(handlers, deps)) { 1422 | return handlers[deps](registry[relMap.id]); 1423 | } 1424 | 1425 | //Synchronous access to one module. If require.get is 1426 | //available (as in the Node adapter), prefer that. 1427 | if (req.get) { 1428 | return req.get(context, deps, relMap, localRequire); 1429 | } 1430 | 1431 | //Normalize module name, if it contains . or .. 1432 | map = makeModuleMap(deps, relMap, false, true); 1433 | id = map.id; 1434 | 1435 | if (!hasProp(defined, id)) { 1436 | return onError(makeError('notloaded', 'Module name "' + 1437 | id + 1438 | '" has not been loaded yet for context: ' + 1439 | contextName + 1440 | (relMap ? '' : '. Use require([])'))); 1441 | } 1442 | return defined[id]; 1443 | } 1444 | 1445 | //Grab defines waiting in the global queue. 1446 | intakeDefines(); 1447 | 1448 | //Mark all the dependencies as needing to be loaded. 1449 | context.nextTick(function () { 1450 | //Some defines could have been added since the 1451 | //require call, collect them. 1452 | intakeDefines(); 1453 | 1454 | requireMod = getModule(makeModuleMap(null, relMap)); 1455 | 1456 | //Store if map config should be applied to this require 1457 | //call for dependencies. 1458 | requireMod.skipMap = options.skipMap; 1459 | 1460 | requireMod.init(deps, callback, errback, { 1461 | enabled: true 1462 | }); 1463 | 1464 | checkLoaded(); 1465 | }); 1466 | 1467 | return localRequire; 1468 | } 1469 | 1470 | mixin(localRequire, { 1471 | isBrowser: isBrowser, 1472 | 1473 | /** 1474 | * Converts a module name + .extension into an URL path. 1475 | * *Requires* the use of a module name. It does not support using 1476 | * plain URLs like nameToUrl. 1477 | */ 1478 | toUrl: function (moduleNamePlusExt) { 1479 | var ext, 1480 | index = moduleNamePlusExt.lastIndexOf('.'), 1481 | segment = moduleNamePlusExt.split('/')[0], 1482 | isRelative = segment === '.' || segment === '..'; 1483 | 1484 | //Have a file extension alias, and it is not the 1485 | //dots from a relative path. 1486 | if (index !== -1 && (!isRelative || index > 1)) { 1487 | ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); 1488 | moduleNamePlusExt = moduleNamePlusExt.substring(0, index); 1489 | } 1490 | 1491 | return context.nameToUrl(normalize(moduleNamePlusExt, 1492 | relMap && relMap.id, true), ext, true); 1493 | }, 1494 | 1495 | defined: function (id) { 1496 | return hasProp(defined, makeModuleMap(id, relMap, false, true).id); 1497 | }, 1498 | 1499 | specified: function (id) { 1500 | id = makeModuleMap(id, relMap, false, true).id; 1501 | return hasProp(defined, id) || hasProp(registry, id); 1502 | } 1503 | }); 1504 | 1505 | //Only allow undef on top level require calls 1506 | if (!relMap) { 1507 | localRequire.undef = function (id) { 1508 | //Bind any waiting define() calls to this context, 1509 | //fix for #408 1510 | takeGlobalQueue(); 1511 | 1512 | var map = makeModuleMap(id, relMap, true), 1513 | mod = getOwn(registry, id); 1514 | 1515 | mod.undefed = true; 1516 | removeScript(id); 1517 | 1518 | delete defined[id]; 1519 | delete urlFetched[map.url]; 1520 | delete undefEvents[id]; 1521 | 1522 | //Clean queued defines too. Go backwards 1523 | //in array so that the splices do not 1524 | //mess up the iteration. 1525 | eachReverse(defQueue, function(args, i) { 1526 | if (args[0] === id) { 1527 | defQueue.splice(i, 1); 1528 | } 1529 | }); 1530 | delete context.defQueueMap[id]; 1531 | 1532 | if (mod) { 1533 | //Hold on to listeners in case the 1534 | //module will be attempted to be reloaded 1535 | //using a different config. 1536 | if (mod.events.defined) { 1537 | undefEvents[id] = mod.events; 1538 | } 1539 | 1540 | cleanRegistry(id); 1541 | } 1542 | }; 1543 | } 1544 | 1545 | return localRequire; 1546 | }, 1547 | 1548 | /** 1549 | * Called to enable a module if it is still in the registry 1550 | * awaiting enablement. A second arg, parent, the parent module, 1551 | * is passed in for context, when this method is overridden by 1552 | * the optimizer. Not shown here to keep code compact. 1553 | */ 1554 | enable: function (depMap) { 1555 | var mod = getOwn(registry, depMap.id); 1556 | if (mod) { 1557 | getModule(depMap).enable(); 1558 | } 1559 | }, 1560 | 1561 | /** 1562 | * Internal method used by environment adapters to complete a load event. 1563 | * A load event could be a script load or just a load pass from a synchronous 1564 | * load call. 1565 | * @param {String} moduleName the name of the module to potentially complete. 1566 | */ 1567 | completeLoad: function (moduleName) { 1568 | var found, args, mod, 1569 | shim = getOwn(config.shim, moduleName) || {}, 1570 | shExports = shim.exports; 1571 | 1572 | takeGlobalQueue(); 1573 | 1574 | while (defQueue.length) { 1575 | args = defQueue.shift(); 1576 | if (args[0] === null) { 1577 | args[0] = moduleName; 1578 | //If already found an anonymous module and bound it 1579 | //to this name, then this is some other anon module 1580 | //waiting for its completeLoad to fire. 1581 | if (found) { 1582 | break; 1583 | } 1584 | found = true; 1585 | } else if (args[0] === moduleName) { 1586 | //Found matching define call for this script! 1587 | found = true; 1588 | } 1589 | 1590 | callGetModule(args); 1591 | } 1592 | context.defQueueMap = {}; 1593 | 1594 | //Do this after the cycle of callGetModule in case the result 1595 | //of those calls/init calls changes the registry. 1596 | mod = getOwn(registry, moduleName); 1597 | 1598 | if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) { 1599 | if (config.enforceDefine && (!shExports || !getGlobal(shExports))) { 1600 | if (hasPathFallback(moduleName)) { 1601 | return; 1602 | } else { 1603 | return onError(makeError('nodefine', 1604 | 'No define call for ' + moduleName, 1605 | null, 1606 | [moduleName])); 1607 | } 1608 | } else { 1609 | //A script that does not call define(), so just simulate 1610 | //the call for it. 1611 | callGetModule([moduleName, (shim.deps || []), shim.exportsFn]); 1612 | } 1613 | } 1614 | 1615 | checkLoaded(); 1616 | }, 1617 | 1618 | /** 1619 | * Converts a module name to a file path. Supports cases where 1620 | * moduleName may actually be just an URL. 1621 | * Note that it **does not** call normalize on the moduleName, 1622 | * it is assumed to have already been normalized. This is an 1623 | * internal API, not a public one. Use toUrl for the public API. 1624 | */ 1625 | nameToUrl: function (moduleName, ext, skipExt) { 1626 | var paths, syms, i, parentModule, url, 1627 | parentPath, bundleId, 1628 | pkgMain = getOwn(config.pkgs, moduleName); 1629 | 1630 | if (pkgMain) { 1631 | moduleName = pkgMain; 1632 | } 1633 | 1634 | bundleId = getOwn(bundlesMap, moduleName); 1635 | 1636 | if (bundleId) { 1637 | return context.nameToUrl(bundleId, ext, skipExt); 1638 | } 1639 | 1640 | //If a colon is in the URL, it indicates a protocol is used and it is just 1641 | //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) 1642 | //or ends with .js, then assume the user meant to use an url and not a module id. 1643 | //The slash is important for protocol-less URLs as well as full paths. 1644 | if (req.jsExtRegExp.test(moduleName)) { 1645 | //Just a plain path, not module name lookup, so just return it. 1646 | //Add extension if it is included. This is a bit wonky, only non-.js things pass 1647 | //an extension, this method probably needs to be reworked. 1648 | url = moduleName + (ext || ''); 1649 | } else { 1650 | //A module that needs to be converted to a path. 1651 | paths = config.paths; 1652 | 1653 | syms = moduleName.split('/'); 1654 | //For each module name segment, see if there is a path 1655 | //registered for it. Start with most specific name 1656 | //and work up from it. 1657 | for (i = syms.length; i > 0; i -= 1) { 1658 | parentModule = syms.slice(0, i).join('/'); 1659 | 1660 | parentPath = getOwn(paths, parentModule); 1661 | if (parentPath) { 1662 | //If an array, it means there are a few choices, 1663 | //Choose the one that is desired 1664 | if (isArray(parentPath)) { 1665 | parentPath = parentPath[0]; 1666 | } 1667 | syms.splice(0, i, parentPath); 1668 | break; 1669 | } 1670 | } 1671 | 1672 | //Join the path parts together, then figure out if baseUrl is needed. 1673 | url = syms.join('/'); 1674 | url += (ext || (/^data\:|^blob\:|\?/.test(url) || skipExt ? '' : '.js')); 1675 | url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; 1676 | } 1677 | 1678 | return config.urlArgs && !/^blob\:/.test(url) ? 1679 | url + config.urlArgs(moduleName, url) : url; 1680 | }, 1681 | 1682 | //Delegates to req.load. Broken out as a separate function to 1683 | //allow overriding in the optimizer. 1684 | load: function (id, url) { 1685 | req.load(context, id, url); 1686 | }, 1687 | 1688 | /** 1689 | * Executes a module callback function. Broken out as a separate function 1690 | * solely to allow the build system to sequence the files in the built 1691 | * layer in the right sequence. 1692 | * 1693 | * @private 1694 | */ 1695 | execCb: function (name, callback, args, exports) { 1696 | return callback.apply(exports, args); 1697 | }, 1698 | 1699 | /** 1700 | * callback for script loads, used to check status of loading. 1701 | * 1702 | * @param {Event} evt the event from the browser for the script 1703 | * that was loaded. 1704 | */ 1705 | onScriptLoad: function (evt) { 1706 | //Using currentTarget instead of target for Firefox 2.0's sake. Not 1707 | //all old browsers will be supported, but this one was easy enough 1708 | //to support and still makes sense. 1709 | if (evt.type === 'load' || 1710 | (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { 1711 | //Reset interactive script so a script node is not held onto for 1712 | //to long. 1713 | interactiveScript = null; 1714 | 1715 | //Pull out the name of the module and the context. 1716 | var data = getScriptData(evt); 1717 | context.completeLoad(data.id); 1718 | } 1719 | }, 1720 | 1721 | /** 1722 | * Callback for script errors. 1723 | */ 1724 | onScriptError: function (evt) { 1725 | var data = getScriptData(evt); 1726 | if (!hasPathFallback(data.id)) { 1727 | var parents = []; 1728 | eachProp(registry, function(value, key) { 1729 | if (key.indexOf('_@r') !== 0) { 1730 | each(value.depMaps, function(depMap) { 1731 | if (depMap.id === data.id) { 1732 | parents.push(key); 1733 | return true; 1734 | } 1735 | }); 1736 | } 1737 | }); 1738 | return onError(makeError('scripterror', 'Script error for "' + data.id + 1739 | (parents.length ? 1740 | '", needed by: ' + parents.join(', ') : 1741 | '"'), evt, [data.id])); 1742 | } 1743 | } 1744 | }; 1745 | 1746 | context.require = context.makeRequire(); 1747 | return context; 1748 | } 1749 | 1750 | /** 1751 | * Main entry point. 1752 | * 1753 | * If the only argument to require is a string, then the module that 1754 | * is represented by that string is fetched for the appropriate context. 1755 | * 1756 | * If the first argument is an array, then it will be treated as an array 1757 | * of dependency string names to fetch. An optional function callback can 1758 | * be specified to execute when all of those dependencies are available. 1759 | * 1760 | * Make a local req variable to help Caja compliance (it assumes things 1761 | * on a require that are not standardized), and to give a short 1762 | * name for minification/local scope use. 1763 | */ 1764 | req = requirejs = function (deps, callback, errback, optional) { 1765 | 1766 | //Find the right context, use default 1767 | var context, config, 1768 | contextName = defContextName; 1769 | 1770 | // Determine if have config object in the call. 1771 | if (!isArray(deps) && typeof deps !== 'string') { 1772 | // deps is a config object 1773 | config = deps; 1774 | if (isArray(callback)) { 1775 | // Adjust args if there are dependencies 1776 | deps = callback; 1777 | callback = errback; 1778 | errback = optional; 1779 | } else { 1780 | deps = []; 1781 | } 1782 | } 1783 | 1784 | if (config && config.context) { 1785 | contextName = config.context; 1786 | } 1787 | 1788 | context = getOwn(contexts, contextName); 1789 | if (!context) { 1790 | context = contexts[contextName] = req.s.newContext(contextName); 1791 | } 1792 | 1793 | if (config) { 1794 | context.configure(config); 1795 | } 1796 | 1797 | return context.require(deps, callback, errback); 1798 | }; 1799 | 1800 | /** 1801 | * Support require.config() to make it easier to cooperate with other 1802 | * AMD loaders on globally agreed names. 1803 | */ 1804 | req.config = function (config) { 1805 | return req(config); 1806 | }; 1807 | 1808 | /** 1809 | * Execute something after the current tick 1810 | * of the event loop. Override for other envs 1811 | * that have a better solution than setTimeout. 1812 | * @param {Function} fn function to execute later. 1813 | */ 1814 | req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) { 1815 | setTimeout(fn, 4); 1816 | } : function (fn) { fn(); }; 1817 | 1818 | /** 1819 | * Export require as a global, but only if it does not already exist. 1820 | */ 1821 | if (!require) { 1822 | require = req; 1823 | } 1824 | 1825 | req.version = version; 1826 | 1827 | //Used to filter out dependencies that are already paths. 1828 | req.jsExtRegExp = /^\/|:|\?|\.js$/; 1829 | req.isBrowser = isBrowser; 1830 | s = req.s = { 1831 | contexts: contexts, 1832 | newContext: newContext 1833 | }; 1834 | 1835 | //Create default context. 1836 | req({}); 1837 | 1838 | //Exports some context-sensitive methods on global require. 1839 | each([ 1840 | 'toUrl', 1841 | 'undef', 1842 | 'defined', 1843 | 'specified' 1844 | ], function (prop) { 1845 | //Reference from contexts instead of early binding to default context, 1846 | //so that during builds, the latest instance of the default context 1847 | //with its config gets used. 1848 | req[prop] = function () { 1849 | var ctx = contexts[defContextName]; 1850 | return ctx.require[prop].apply(ctx, arguments); 1851 | }; 1852 | }); 1853 | 1854 | if (isBrowser) { 1855 | head = s.head = document.getElementsByTagName('head')[0]; 1856 | //If BASE tag is in play, using appendChild is a problem for IE6. 1857 | //When that browser dies, this can be removed. Details in this jQuery bug: 1858 | //http://dev.jquery.com/ticket/2709 1859 | baseElement = document.getElementsByTagName('base')[0]; 1860 | if (baseElement) { 1861 | head = s.head = baseElement.parentNode; 1862 | } 1863 | } 1864 | 1865 | /** 1866 | * Any errors that require explicitly generates will be passed to this 1867 | * function. Intercept/override it if you want custom error handling. 1868 | * @param {Error} err the error object. 1869 | */ 1870 | req.onError = defaultOnError; 1871 | 1872 | /** 1873 | * Creates the node for the load command. Only used in browser envs. 1874 | */ 1875 | req.createNode = function (config, moduleName, url) { 1876 | var node = config.xhtml ? 1877 | document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : 1878 | document.createElement('script'); 1879 | node.type = config.scriptType || 'text/javascript'; 1880 | node.charset = 'utf-8'; 1881 | node.async = true; 1882 | return node; 1883 | }; 1884 | 1885 | /** 1886 | * Does the request to load a module for the browser case. 1887 | * Make this a separate function to allow other environments 1888 | * to override it. 1889 | * 1890 | * @param {Object} context the require context to find state. 1891 | * @param {String} moduleName the name of the module. 1892 | * @param {Object} url the URL to the module. 1893 | */ 1894 | req.load = function (context, moduleName, url) { 1895 | var config = (context && context.config) || {}, 1896 | node; 1897 | if (isBrowser) { 1898 | //In the browser so use a script tag 1899 | node = req.createNode(config, moduleName, url); 1900 | 1901 | node.setAttribute('data-requirecontext', context.contextName); 1902 | node.setAttribute('data-requiremodule', moduleName); 1903 | 1904 | //Set up load listener. Test attachEvent first because IE9 has 1905 | //a subtle issue in its addEventListener and script onload firings 1906 | //that do not match the behavior of all other browsers with 1907 | //addEventListener support, which fire the onload event for a 1908 | //script right after the script execution. See: 1909 | //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution 1910 | //UNFORTUNATELY Opera implements attachEvent but does not follow the script 1911 | //script execution mode. 1912 | if (node.attachEvent && 1913 | //Check if node.attachEvent is artificially added by custom script or 1914 | //natively supported by browser 1915 | //read https://github.com/requirejs/requirejs/issues/187 1916 | //if we can NOT find [native code] then it must NOT natively supported. 1917 | //in IE8, node.attachEvent does not have toString() 1918 | //Note the test for "[native code" with no closing brace, see: 1919 | //https://github.com/requirejs/requirejs/issues/273 1920 | !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && 1921 | !isOpera) { 1922 | //Probably IE. IE (at least 6-8) do not fire 1923 | //script onload right after executing the script, so 1924 | //we cannot tie the anonymous define call to a name. 1925 | //However, IE reports the script as being in 'interactive' 1926 | //readyState at the time of the define call. 1927 | useInteractive = true; 1928 | 1929 | node.attachEvent('onreadystatechange', context.onScriptLoad); 1930 | //It would be great to add an error handler here to catch 1931 | //404s in IE9+. However, onreadystatechange will fire before 1932 | //the error handler, so that does not help. If addEventListener 1933 | //is used, then IE will fire error before load, but we cannot 1934 | //use that pathway given the connect.microsoft.com issue 1935 | //mentioned above about not doing the 'script execute, 1936 | //then fire the script load event listener before execute 1937 | //next script' that other browsers do. 1938 | //Best hope: IE10 fixes the issues, 1939 | //and then destroys all installs of IE 6-9. 1940 | //node.attachEvent('onerror', context.onScriptError); 1941 | } else { 1942 | node.addEventListener('load', context.onScriptLoad, false); 1943 | node.addEventListener('error', context.onScriptError, false); 1944 | } 1945 | node.src = url; 1946 | 1947 | //Calling onNodeCreated after all properties on the node have been 1948 | //set, but before it is placed in the DOM. 1949 | if (config.onNodeCreated) { 1950 | config.onNodeCreated(node, config, moduleName, url); 1951 | } 1952 | 1953 | //For some cache cases in IE 6-8, the script executes before the end 1954 | //of the appendChild execution, so to tie an anonymous define 1955 | //call to the module name (which is stored on the node), hold on 1956 | //to a reference to this node, but clear after the DOM insertion. 1957 | currentlyAddingScript = node; 1958 | if (baseElement) { 1959 | head.insertBefore(node, baseElement); 1960 | } else { 1961 | head.appendChild(node); 1962 | } 1963 | currentlyAddingScript = null; 1964 | 1965 | return node; 1966 | } else if (isWebWorker) { 1967 | try { 1968 | //In a web worker, use importScripts. This is not a very 1969 | //efficient use of importScripts, importScripts will block until 1970 | //its script is downloaded and evaluated. However, if web workers 1971 | //are in play, the expectation is that a build has been done so 1972 | //that only one script needs to be loaded anyway. This may need 1973 | //to be reevaluated if other use cases become common. 1974 | 1975 | // Post a task to the event loop to work around a bug in WebKit 1976 | // where the worker gets garbage-collected after calling 1977 | // importScripts(): https://webkit.org/b/153317 1978 | setTimeout(function() {}, 0); 1979 | importScripts(url); 1980 | 1981 | //Account for anonymous modules 1982 | context.completeLoad(moduleName); 1983 | } catch (e) { 1984 | context.onError(makeError('importscripts', 1985 | 'importScripts failed for ' + 1986 | moduleName + ' at ' + url, 1987 | e, 1988 | [moduleName])); 1989 | } 1990 | } 1991 | }; 1992 | 1993 | function getInteractiveScript() { 1994 | if (interactiveScript && interactiveScript.readyState === 'interactive') { 1995 | return interactiveScript; 1996 | } 1997 | 1998 | eachReverse(scripts(), function (script) { 1999 | if (script.readyState === 'interactive') { 2000 | return (interactiveScript = script); 2001 | } 2002 | }); 2003 | return interactiveScript; 2004 | } 2005 | 2006 | //Look for a data-main script attribute, which could also adjust the baseUrl. 2007 | if (isBrowser && !cfg.skipDataMain) { 2008 | //Figure out baseUrl. Get it from the script tag with require.js in it. 2009 | eachReverse(scripts(), function (script) { 2010 | //Set the 'head' where we can append children by 2011 | //using the script's parent. 2012 | if (!head) { 2013 | head = script.parentNode; 2014 | } 2015 | 2016 | //Look for a data-main attribute to set main script for the page 2017 | //to load. If it is there, the path to data main becomes the 2018 | //baseUrl, if it is not already set. 2019 | dataMain = script.getAttribute('data-main'); 2020 | if (dataMain) { 2021 | //Preserve dataMain in case it is a path (i.e. contains '?') 2022 | mainScript = dataMain; 2023 | 2024 | //Set final baseUrl if there is not already an explicit one, 2025 | //but only do so if the data-main value is not a loader plugin 2026 | //module ID. 2027 | if (!cfg.baseUrl && mainScript.indexOf('!') === -1) { 2028 | //Pull off the directory of data-main for use as the 2029 | //baseUrl. 2030 | src = mainScript.split('/'); 2031 | mainScript = src.pop(); 2032 | subPath = src.length ? src.join('/') + '/' : './'; 2033 | 2034 | cfg.baseUrl = subPath; 2035 | } 2036 | 2037 | //Strip off any trailing .js since mainScript is now 2038 | //like a module name. 2039 | mainScript = mainScript.replace(jsSuffixRegExp, ''); 2040 | 2041 | //If mainScript is still a path, fall back to dataMain 2042 | if (req.jsExtRegExp.test(mainScript)) { 2043 | mainScript = dataMain; 2044 | } 2045 | 2046 | //Put the data-main script in the files to load. 2047 | cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript]; 2048 | 2049 | return true; 2050 | } 2051 | }); 2052 | } 2053 | 2054 | /** 2055 | * The function that handles definitions of modules. Differs from 2056 | * require() in that a string for the module should be the first argument, 2057 | * and the function to execute after dependencies are loaded should 2058 | * return a value to define the module corresponding to the first argument's 2059 | * name. 2060 | */ 2061 | define = function (name, deps, callback) { 2062 | var node, context; 2063 | 2064 | //Allow for anonymous modules 2065 | if (typeof name !== 'string') { 2066 | //Adjust args appropriately 2067 | callback = deps; 2068 | deps = name; 2069 | name = null; 2070 | } 2071 | 2072 | //This module may not have dependencies 2073 | if (!isArray(deps)) { 2074 | callback = deps; 2075 | deps = null; 2076 | } 2077 | 2078 | //If no name, and callback is a function, then figure out if it a 2079 | //CommonJS thing with dependencies. 2080 | if (!deps && isFunction(callback)) { 2081 | deps = []; 2082 | //Remove comments from the callback string, 2083 | //look for require calls, and pull them into the dependencies, 2084 | //but only if there are function args. 2085 | if (callback.length) { 2086 | callback 2087 | .toString() 2088 | .replace(commentRegExp, commentReplace) 2089 | .replace(cjsRequireRegExp, function (match, dep) { 2090 | deps.push(dep); 2091 | }); 2092 | 2093 | //May be a CommonJS thing even without require calls, but still 2094 | //could use exports, and module. Avoid doing exports and module 2095 | //work though if it just needs require. 2096 | //REQUIRES the function to expect the CommonJS variables in the 2097 | //order listed below. 2098 | deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps); 2099 | } 2100 | } 2101 | 2102 | //If in IE 6-8 and hit an anonymous define() call, do the interactive 2103 | //work. 2104 | if (useInteractive) { 2105 | node = currentlyAddingScript || getInteractiveScript(); 2106 | if (node) { 2107 | if (!name) { 2108 | name = node.getAttribute('data-requiremodule'); 2109 | } 2110 | context = contexts[node.getAttribute('data-requirecontext')]; 2111 | } 2112 | } 2113 | 2114 | //Always save off evaluating the def call until the script onload handler. 2115 | //This allows multiple modules to be in a file without prematurely 2116 | //tracing dependencies, and allows for anonymous module support, 2117 | //where the module name is not known until the script onload event 2118 | //occurs. If no context, use the global queue, and get it processed 2119 | //in the onscript load callback. 2120 | if (context) { 2121 | context.defQueue.push([name, deps, callback]); 2122 | context.defQueueMap[name] = true; 2123 | } else { 2124 | globalDefQueue.push([name, deps, callback]); 2125 | } 2126 | }; 2127 | 2128 | define.amd = { 2129 | jQuery: true 2130 | }; 2131 | 2132 | /** 2133 | * Executes the text. Normally just uses eval, but can be modified 2134 | * to use a better, environment-specific call. Only used for transpiling 2135 | * loader plugins, not for plain JS modules. 2136 | * @param {String} text the text to execute/evaluate. 2137 | */ 2138 | req.exec = function (text) { 2139 | /*jslint evil: true */ 2140 | return eval(text); 2141 | }; 2142 | 2143 | //Set up with config info. 2144 | req(cfg); 2145 | }(this, (typeof setTimeout === 'undefined' ? undefined : setTimeout))); 2146 | --------------------------------------------------------------------------------