From c89bef2762473d2f70e9f62ce6eed54bfde2af71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Wed, 6 May 2015 19:58:29 +0200 Subject: [PATCH 001/103] FIX: proper regex for search terms --- lib/search.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/search.rb b/lib/search.rb index 454aa5b7c5..97779db687 100644 --- a/lib/search.rb +++ b/lib/search.rb @@ -426,7 +426,7 @@ class Search def self.ts_query(term, locale = nil, joiner = "&") locale = Post.sanitize(locale) if locale - all_terms = term.gsub(/[*:()&!'"]/,'').squish.split + all_terms = term.gsub(/[\p{P}\p{S}]+/, ' ').squish.split query = Post.sanitize(all_terms.map {|t| "#{PG::Connection.escape_string(t)}:*"}.join(" #{joiner} ")) "TO_TSQUERY(#{locale || query_locale}, #{query})" end From 52c19d74f8c33b47ec4f1fe5e2785b07f20338c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Wed, 6 May 2015 23:56:34 +0200 Subject: [PATCH 002/103] FIX: error when user name was nil --- app/mailers/user_notifications.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/mailers/user_notifications.rb b/app/mailers/user_notifications.rb index af2e01ad99..7ae1b8810a 100644 --- a/app/mailers/user_notifications.rb +++ b/app/mailers/user_notifications.rb @@ -142,7 +142,7 @@ class UserNotifications < ActionMailer::Base title: post.topic.title, post: post, username: post.user.username, - from_alias: (SiteSetting.enable_names && SiteSetting.display_name_on_posts && !post.user.name.empty?) ? post.user.name : post.user.username, + from_alias: (SiteSetting.enable_names && SiteSetting.display_name_on_posts && post.user.name.present?) ? post.user.name : post.user.username, allow_reply_by_email: true, use_site_subject: true, add_re_to_subject: true, From 9a96cd9f3bca6f93ed98d6075fd1a9a894041a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Thu, 7 May 2015 01:00:13 +0200 Subject: [PATCH 003/103] CRUSHED: duplicate key value violates unique constraint 'index_uploads_on_sha1' --- app/jobs/scheduled/create_missing_avatars.rb | 12 ++++--- app/models/user_avatar.rb | 38 +++++++++++--------- lib/discourse.rb | 2 +- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/app/jobs/scheduled/create_missing_avatars.rb b/app/jobs/scheduled/create_missing_avatars.rb index 42a2b01dc8..8526b41155 100644 --- a/app/jobs/scheduled/create_missing_avatars.rb +++ b/app/jobs/scheduled/create_missing_avatars.rb @@ -1,13 +1,15 @@ module Jobs class CreateMissingAvatars < Jobs::Scheduled every 1.hour + def execute(args) - # backfill in batches 5000 an hour - UserAvatar.where(last_gravatar_download_attempt: nil).includes(:user) - .order("users.last_posted_at desc") - .limit(5000).each do |u| + # backfill in batches of 5000 an hour + UserAvatar.includes(:user) + .where(last_gravatar_download_attempt: nil) + .order("users.last_posted_at DESC") + .limit(5000) + .each do |u| u.user.refresh_avatar - u.user.save end end end diff --git a/app/models/user_avatar.rb b/app/models/user_avatar.rb index 73431a9610..0a14ec745c 100644 --- a/app/models/user_avatar.rb +++ b/app/models/user_avatar.rb @@ -10,27 +10,31 @@ class UserAvatar < ActiveRecord::Base end def update_gravatar! - # special logic for our system user, we do not want the discourse email there - email_hash = user.id == -1 ? User.email_hash("info@discourse.org") : user.email_hash + DistributedMutex.synchronize("update_gravatar_#{user.id}") do + begin + # special logic for our system user + email_hash = user.id == Discourse::SYSTEM_USER_ID ? User.email_hash("info@discourse.org") : user.email_hash - self.last_gravatar_download_attempt = Time.new - gravatar_url = "http://www.gravatar.com/avatar/#{email_hash}.png?s=500&d=404" - tempfile = FileHelper.download(gravatar_url, SiteSetting.max_image_size_kb.kilobytes, "gravatar") + self.last_gravatar_download_attempt = Time.new - upload = Upload.create_for(user.id, tempfile, 'gravatar.png', tempfile.size, { origin: gravatar_url }) + gravatar_url = "http://www.gravatar.com/avatar/#{email_hash}.png?s=500&d=404" + tempfile = FileHelper.download(gravatar_url, SiteSetting.max_image_size_kb.kilobytes, "gravatar") + upload = Upload.create_for(user.id, tempfile, 'gravatar.png', tempfile.size, { origin: gravatar_url }) - if gravatar_upload_id != upload.id - gravatar_upload.try(:destroy!) - self.gravatar_upload = upload - save! + if gravatar_upload_id != upload.id + gravatar_upload.try(:destroy!) + self.gravatar_upload = upload + save! + end + rescue OpenURI::HTTPError + save! + rescue SocketError + # skip saving, we are not connected to the net + Rails.logger.warn "Failed to download gravatar, socket error - user id #{user.id}" + ensure + tempfile.try(:close!) + end end - rescue OpenURI::HTTPError - save! - rescue SocketError - # skip saving, we are not connected to the net - Rails.logger.warn "Failed to download gravatar, socket error - user id #{user.id}" - ensure - tempfile.close! if tempfile && tempfile.respond_to?(:close!) end end diff --git a/lib/discourse.rb b/lib/discourse.rb index 2a139eb2d7..845aaf4824 100644 --- a/lib/discourse.rb +++ b/lib/discourse.rb @@ -256,7 +256,7 @@ module Discourse user ||= User.admins.real.order(:id).first end - SYSTEM_USER_ID = -1 unless defined? SYSTEM_USER_ID + SYSTEM_USER_ID ||= -1 def self.system_user User.find_by(id: SYSTEM_USER_ID) From d6c06eb547e45cce97930e528aed2705574e43a3 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 May 2015 10:42:21 +1000 Subject: [PATCH 004/103] Get rid of CSRF errors --- config/initializers/logster.rb | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/config/initializers/logster.rb b/config/initializers/logster.rb index c1d862dba9..013e1b3c36 100644 --- a/config/initializers/logster.rb +++ b/config/initializers/logster.rb @@ -20,14 +20,9 @@ if Rails.env.production? # /(?m).*?Line: (?:\D|0).*?Column: (?:\D|0)/, - # suppress trackback spam bots - Logster::IgnorePattern.new("Can't verify CSRF token authenticity", { REQUEST_URI: /\/trackback\/$/ }), - # suppress trackback spam bots submitting to random URLs - # test for the presence of these params: url, title, excerpt, blog_name - Logster::IgnorePattern.new("Can't verify CSRF token authenticity", { params: { url: /./, title: /./, excerpt: /./, blog_name: /./} }), - - # API calls, TODO fix this in rails - Logster::IgnorePattern.new("Can't verify CSRF token authenticity", { REQUEST_URI: /api_key/ }) + # CSRF errors are not providing enough data + # suppress unconditionally for now + /^Can't verify CSRF token authenticity$/ ] end From 4167757dee7814df254d408d539e82630136708a Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 May 2015 10:49:29 +1000 Subject: [PATCH 005/103] correct exception when page is sent in as array --- lib/topic_view.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/topic_view.rb b/lib/topic_view.rb index 2fe19b7561..c4e23aef6b 100644 --- a/lib/topic_view.rb +++ b/lib/topic_view.rb @@ -38,7 +38,9 @@ class TopicView self.instance_variable_set("@#{key}".to_sym, value) end - @page = @page.to_i + # work around people somehow sending in arrays, + # arrays are not supported + @page = @page.to_i rescue 1 @page = 1 if @page.zero? @chunk_size = options[:slow_platform] ? TopicView.slow_chunk_size : TopicView.chunk_size @limit ||= @chunk_size From 77cc087b1377ac395862eef9577759ad7ab0d8da Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 May 2015 11:00:22 +1000 Subject: [PATCH 006/103] FIX: proper error message when account created is hit with no session --- app/controllers/users_controller.rb | 2 +- config/locales/server.en.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 3858dd11ca..b83398ad1d 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -436,7 +436,7 @@ class UsersController < ApplicationController end def account_created - @message = session['user_created_message'] + @message = session['user_created_message'] || I18n.t('activation.missing_session') expires_now render layout: 'no_ember' end diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 8fba30e700..76c2b5ffe1 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -475,7 +475,7 @@ en: continue_button: "Continue to %{site_name}" welcome_to: "Welcome to %{site_name}!" approval_required: "A moderator must manually approve your new account before you can access this forum. You'll get an email when your account is approved!" - + missing_session: "We can not detect if your account was created, please ensure you have cookies enabled." post_action_types: off_topic: title: 'Off-Topic' From 8277a586bbdf79d169bcefc9ac618b93261487a7 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 May 2015 11:00:51 +1000 Subject: [PATCH 007/103] usage of raise corrected --- app/controllers/admin/api_controller.rb | 4 ++-- app/controllers/admin/reports_controller.rb | 4 ++-- app/controllers/admin/users_controller.rb | 2 +- app/controllers/application_controller.rb | 2 +- app/controllers/list_controller.rb | 4 ++-- app/controllers/user_badges_controller.rb | 2 +- app/controllers/users_controller.rb | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/controllers/admin/api_controller.rb b/app/controllers/admin/api_controller.rb index 57d9bce4e9..9fd25eecfb 100644 --- a/app/controllers/admin/api_controller.rb +++ b/app/controllers/admin/api_controller.rb @@ -6,7 +6,7 @@ class Admin::ApiController < Admin::AdminController def regenerate_key api_key = ApiKey.find_by(id: params[:id]) - raise Discourse::NotFound.new if api_key.blank? + raise Discourse::NotFound if api_key.blank? api_key.regenerate!(current_user) render_serialized(api_key, ApiKeySerializer) @@ -14,7 +14,7 @@ class Admin::ApiController < Admin::AdminController def revoke_key api_key = ApiKey.find_by(id: params[:id]) - raise Discourse::NotFound.new if api_key.blank? + raise Discourse::NotFound if api_key.blank? api_key.destroy render nothing: true diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb index fe6408ccd8..cd9b7c8541 100644 --- a/app/controllers/admin/reports_controller.rb +++ b/app/controllers/admin/reports_controller.rb @@ -5,7 +5,7 @@ class Admin::ReportsController < Admin::AdminController def show report_type = params[:type] - raise Discourse::NotFound.new unless report_type =~ /^[a-z0-9\_]+$/ + raise Discourse::NotFound unless report_type =~ /^[a-z0-9\_]+$/ start_date = 1.month.ago start_date = Time.parse(params[:start_date]) if params[:start_date].present? @@ -14,7 +14,7 @@ class Admin::ReportsController < Admin::AdminController end_date = Time.parse(params[:end_date]) if params[:end_date].present? report = Report.find(report_type, {start_date: start_date, end_date: end_date}) - raise Discourse::NotFound.new if report.blank? + raise Discourse::NotFound if report.blank? render_json_dump(report: report) end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index c1194709f5..977d1e28d7 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -38,7 +38,7 @@ class Admin::UsersController < Admin::AdminController def show @user = User.find_by(username_lower: params[:id]) - raise Discourse::NotFound.new unless @user + raise Discourse::NotFound unless @user render_serialized(@user, AdminDetailedUserSerializer, root: false) end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1c9bdbbd8e..6775cdf539 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -261,7 +261,7 @@ class ApplicationController < ActionController::Base elsif params[:external_id] SingleSignOnRecord.find_by(external_id: params[:external_id]).try(:user) end - raise Discourse::NotFound.new if user.blank? + raise Discourse::NotFound if user.blank? guardian.ensure_can_see!(user) user diff --git a/app/controllers/list_controller.rb b/app/controllers/list_controller.rb index 2cc4669084..e6e30a54c1 100644 --- a/app/controllers/list_controller.rb +++ b/app/controllers/list_controller.rb @@ -225,11 +225,11 @@ class ListController < ApplicationController parent_category_id = nil if parent_slug_or_id.present? parent_category_id = Category.query_parent_category(parent_slug_or_id) - raise Discourse::NotFound.new if parent_category_id.blank? + raise Discourse::NotFound if parent_category_id.blank? end @category = Category.query_category(slug_or_id, parent_category_id) - raise Discourse::NotFound.new if !@category + raise Discourse::NotFound if !@category @description_meta = @category.description guardian.ensure_can_see!(@category) diff --git a/app/controllers/user_badges_controller.rb b/app/controllers/user_badges_controller.rb index 8ab55b2e26..397ce503fb 100644 --- a/app/controllers/user_badges_controller.rb +++ b/app/controllers/user_badges_controller.rb @@ -85,7 +85,7 @@ class UserBadgesController < ApplicationController else badge = Badge.find_by(name: params[:badge_name], enabled: true) end - raise Discourse::NotFound.new if badge.blank? + raise Discourse::NotFound if badge.blank? badge end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index b83398ad1d..dc168a565d 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -157,7 +157,7 @@ class UsersController < ApplicationController redirect_to path("/users/#{current_user.username}/#{params[:path]}") return end - raise Discourse::NotFound.new + raise Discourse::NotFound end def invited From d676bbc3498c007017753bc978448bf2ddd5dc29 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 May 2015 11:06:42 +1000 Subject: [PATCH 008/103] handle invalid param gracefully --- app/models/incoming_link.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/incoming_link.rb b/app/models/incoming_link.rb index 9064b0d0d0..fd3e9e8e8d 100644 --- a/app/models/incoming_link.rb +++ b/app/models/incoming_link.rb @@ -14,7 +14,9 @@ class IncomingLink < ActiveRecord::Base user_id, host, referer = nil current_user = opts[:current_user] - if username = opts[:username] + username = opts[:username] + username = nil unless String === username + if username u = User.select(:id).find_by(username_lower: username.downcase) user_id = u.id if u end From 4f53b85ee2bf293af6ff3e9f67f83f02700cccbe Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 May 2015 12:03:20 +1000 Subject: [PATCH 009/103] add aria-label to composer buttons --- app/assets/javascripts/discourse/lib/Markdown.Editor.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/javascripts/discourse/lib/Markdown.Editor.js b/app/assets/javascripts/discourse/lib/Markdown.Editor.js index 3a45faaae7..8b680db6aa 100644 --- a/app/assets/javascripts/discourse/lib/Markdown.Editor.js +++ b/app/assets/javascripts/discourse/lib/Markdown.Editor.js @@ -1403,6 +1403,10 @@ xPosition += 25; button.id = id + postfix; button.title = title; + // we really should just use jquery here + if (button.setAttribute) { + button.setAttribute('aria-label', title); + } if (textOp) button.textOp = textOp; setupButton(button, true); From 4191d97d48e2451ff583ed808dee081544a34d14 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 May 2015 12:14:12 +1000 Subject: [PATCH 010/103] FIX: missing titles and aria-labels on sharing links --- .../javascripts/discourse/initializers/sharing-sources.js.es6 | 4 ++++ .../discourse/templates/components/share-source.hbs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/initializers/sharing-sources.js.es6 b/app/assets/javascripts/discourse/initializers/sharing-sources.js.es6 index e48f4a9d12..803717002c 100644 --- a/app/assets/javascripts/discourse/initializers/sharing-sources.js.es6 +++ b/app/assets/javascripts/discourse/initializers/sharing-sources.js.es6 @@ -19,12 +19,14 @@ export default { return "http://twitter.com/intent/tweet?url=" + encodeURIComponent(link) + "&text=" + encodeURIComponent(title); }, shouldOpenInPopup: true, + title: I18n.t('share.twitter'), popupHeight: 265 }); Sharing.addSource({ id: 'facebook', faIcon: 'fa-facebook-square', + title: I18n.t('share.facebook'), generateUrl: function(link, title) { return "http://www.facebook.com/sharer.php?u=" + encodeURIComponent(link) + '&t=' + encodeURIComponent(title); }, @@ -34,6 +36,7 @@ export default { Sharing.addSource({ id: 'google+', faIcon: 'fa-google-plus-square', + title: I18n.t('share.google+'), generateUrl: function(link) { return "https://plus.google.com/share?url=" + encodeURIComponent(link); }, @@ -44,6 +47,7 @@ export default { Sharing.addSource({ id: 'email', faIcon: 'fa-envelope-square', + title: I18n.t('share.email'), generateUrl: function(link, title) { return "mailto:?to=&subject=" + encodeURIComponent('[' + Discourse.SiteSettings.title + '] ' + title) + "&body=" + encodeURIComponent(link); } diff --git a/app/assets/javascripts/discourse/templates/components/share-source.hbs b/app/assets/javascripts/discourse/templates/components/share-source.hbs index aca17c8b79..87248269b7 100644 --- a/app/assets/javascripts/discourse/templates/components/share-source.hbs +++ b/app/assets/javascripts/discourse/templates/components/share-source.hbs @@ -1,4 +1,4 @@ - + {{#if source.faIcon}} {{else}} From b7897d24b1d628be392034451757aba8ba6aeb82 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 May 2015 13:52:26 +1000 Subject: [PATCH 011/103] keep working even if username is blank --- app/models/discourse_single_sign_on.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/discourse_single_sign_on.rb b/app/models/discourse_single_sign_on.rb index 4db846f93b..db2387923a 100644 --- a/app/models/discourse_single_sign_on.rb +++ b/app/models/discourse_single_sign_on.rb @@ -120,7 +120,7 @@ class DiscourseSingleSignOn < SingleSignOn end if SiteSetting.sso_overrides_name && user.name != name - user.name = name || User.suggest_name(username || email) + user.name = name || User.suggest_name(username.blank? ? email : username) end if SiteSetting.sso_overrides_avatar && avatar_url.present? && ( From 8a3a02421a39f53b6adf3ca9a6fdba73f42bc932 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 May 2015 14:08:27 +1000 Subject: [PATCH 012/103] update onebox gem --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2cd643c0b5..9542962a0c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -271,7 +271,7 @@ GEM omniauth-twitter (1.0.1) multi_json (~> 1.3) omniauth-oauth (~> 1.0) - onebox (1.5.16) + onebox (1.5.17) moneta (~> 0.7) multi_json (~> 1.7) mustache (~> 0.99) From 78cff468bc05ce3c967aa20e881fa753d7869eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Thu, 7 May 2015 15:19:23 +0200 Subject: [PATCH 013/103] FIX: poll options display issues --- plugins/poll/assets/stylesheets/poll.scss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/poll/assets/stylesheets/poll.scss b/plugins/poll/assets/stylesheets/poll.scss index bc03b5200a..cfc85c8f75 100644 --- a/plugins/poll/assets/stylesheets/poll.scss +++ b/plugins/poll/assets/stylesheets/poll.scss @@ -29,10 +29,9 @@ div.poll { color: $option-foreground; background: $option-background; box-shadow: inset 0 -6px rgba(0,0,0,.25), inset 0 0 0 100px rgba(0,0,0,0); - padding: 0 12px; + padding: .5em .7em; margin-bottom: 10px; border-radius: 4px; - height: 2.3em; &:hover { box-shadow: inset 0 -6px rgba(0,0,0,.35), inset 0 0 0 100px rgba(0,0,0,.1); From 9b0ca60f52d256b4e937d4f191adb04536ca950d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Thu, 7 May 2015 16:40:14 +0200 Subject: [PATCH 014/103] FIX: support quotes for poll parameters --- plugins/poll/assets/javascripts/poll_dialect.js | 7 ++++--- plugins/poll/spec/controllers/posts_controller_spec.rb | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/poll/assets/javascripts/poll_dialect.js b/plugins/poll/assets/javascripts/poll_dialect.js index 01c8ff37c7..99bafe65fd 100644 --- a/plugins/poll/assets/javascripts/poll_dialect.js +++ b/plugins/poll/assets/javascripts/poll_dialect.js @@ -8,7 +8,7 @@ const WHITELISTED_ATTRIBUTES = ["type", "name", "min", "max", "step", "order", "color", "background", "status"]; const WHITELISTED_STYLES = ["color", "background"]; - const ATTRIBUTES_REGEX = new RegExp("(" + WHITELISTED_ATTRIBUTES.join("|") + ")=[^\\s\\]]+", "g"); + const ATTRIBUTES_REGEX = new RegExp("(" + WHITELISTED_ATTRIBUTES.join("|") + ")=['\"]?[^\\s\\]]+['\"]?", "g"); Discourse.Dialect.replaceBlock({ start: /\[poll([^\]]*)\]([\s\S]*)/igm, @@ -44,8 +44,9 @@ // extract poll attributes (matches[1].match(ATTRIBUTES_REGEX) || []).forEach(function(m) { - var attr = m.split("="); - attributes[DATA_PREFIX + attr[0]] = attr[1]; + var attr = m.split("="), name = attr[0], value = attr[1]; + value = value.replace(/["']/g, ""); + attributes[DATA_PREFIX + name] = value; }); // we might need these values later... diff --git a/plugins/poll/spec/controllers/posts_controller_spec.rb b/plugins/poll/spec/controllers/posts_controller_spec.rb index 0862586531..7c5263bfca 100644 --- a/plugins/poll/spec/controllers/posts_controller_spec.rb +++ b/plugins/poll/spec/controllers/posts_controller_spec.rb @@ -112,14 +112,14 @@ describe PostsController do describe "named polls" do it "should have different options" do - xhr :post, :create, { title: title, raw: "[poll name=foo]\n- A\n- A[/poll]" } + xhr :post, :create, { title: title, raw: "[poll name=""foo""]\n- A\n- A[/poll]" } expect(response).not_to be_success json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.named_poll_must_have_different_options", name: "foo")) end it "should have at least 2 options" do - xhr :post, :create, { title: title, raw: "[poll name=foo]\n- A[/poll]" } + xhr :post, :create, { title: title, raw: "[poll name='foo']\n- A[/poll]" } expect(response).not_to be_success json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.named_poll_must_have_at_least_2_options", name: "foo")) From c1bb7bc7cc54059073b1dccc83a707936ca16b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Thu, 7 May 2015 17:24:35 +0200 Subject: [PATCH 015/103] clarify copy when editing a poll after the first 5 minutes --- plugins/poll/config/locales/server.en.yml | 6 ++++-- plugins/poll/plugin.rb | 10 +++++----- plugins/poll/spec/controllers/posts_controller_spec.rb | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/plugins/poll/config/locales/server.en.yml b/plugins/poll/config/locales/server.en.yml index 1590536aff..b1d5582c25 100644 --- a/plugins/poll/config/locales/server.en.yml +++ b/plugins/poll/config/locales/server.en.yml @@ -24,8 +24,10 @@ en: named_poll_must_have_different_options: "Poll named %{name} must have different options." requires_at_least_1_valid_option: "You must select at least 1 valid option." - cannot_change_polls_after_5_minutes: "Polls cannot be changed after the first 5 minutes. Contact a moderator if you need to change them." - staff_cannot_add_or_remove_options_after_5_minutes: "After the first 5 minutes, poll options can only be edited, not added or removed. If you need to add or remove options, you should close this topic and create a new one." + + cannot_change_polls_after_5_minutes: "You cannot add, remove or rename polls after the first 5 minutes." + op_cannot_edit_options_after_5_minutes: "You cannot add or remove poll options after the first 5 minutes. Please contact a moderator if you need to edit a poll option." + staff_cannot_add_or_remove_options_after_5_minutes: "You cannot add or remove poll options after the first 5 minutes. You should close this topic and create a new one instead." no_polls_associated_with_this_post: "No polls are associated with this post." no_poll_with_this_name: "No poll named %{name} associated with this post." diff --git a/plugins/poll/plugin.rb b/plugins/poll/plugin.rb index e623fdb374..ebf12d7ad0 100644 --- a/plugins/poll/plugin.rb +++ b/plugins/poll/plugin.rb @@ -260,10 +260,10 @@ after_initialize do if polls.keys != previous_polls.keys || polls.values.map { |p| p["options"] } != previous_polls.values.map { |p| p["options"] } - # outside the 5-minute edit window? + # outside of the 5-minute edit window? if post.created_at < 5.minutes.ago - # cannot add/remove/change/re-order polls - if polls.keys != previous_polls.keys + # cannot add/remove/rename polls + if polls.keys.sort != previous_polls.keys.sort post.errors.add(:base, I18n.t("poll.cannot_change_polls_after_5_minutes")) return end @@ -278,8 +278,8 @@ after_initialize do end end else - # OP cannot change polls - post.errors.add(:base, I18n.t("poll.cannot_change_polls_after_5_minutes")) + # OP cannot edit poll options + post.errors.add(:base, I18n.t("poll.op_cannot_edit_options_after_5_minutes")) return end end diff --git a/plugins/poll/spec/controllers/posts_controller_spec.rb b/plugins/poll/spec/controllers/posts_controller_spec.rb index 7c5263bfca..780789129e 100644 --- a/plugins/poll/spec/controllers/posts_controller_spec.rb +++ b/plugins/poll/spec/controllers/posts_controller_spec.rb @@ -92,7 +92,7 @@ describe PostsController do xhr :put, :update, { id: post_id, post: { raw: new_raw } } expect(response).not_to be_success json = ::JSON.parse(response.body) - expect(json["errors"][0]).to eq(I18n.t("poll.cannot_change_polls_after_5_minutes")) + expect(json["errors"][0]).to eq(I18n.t("poll.op_cannot_edit_options_after_5_minutes")) end it "can be edited by staff" do From 875a013ec76e7ce0cbb95a61223cbbd16ed31d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Thu, 7 May 2015 19:49:06 +0200 Subject: [PATCH 016/103] FIX: poll design on mobile --- .../javascripts/discourse/templates/poll.hbs | 30 ++++++++-------- .../poll/assets/javascripts/poll_dialect.js | 10 +++--- .../assets/stylesheets/{ => common}/poll.scss | 19 ----------- .../poll/assets/stylesheets/desktop/poll.scss | 34 +++++++++++++++++++ .../poll/assets/stylesheets/mobile/poll.scss | 7 ++++ plugins/poll/plugin.rb | 5 ++- 6 files changed, 65 insertions(+), 40 deletions(-) rename plugins/poll/assets/stylesheets/{ => common}/poll.scss (86%) create mode 100644 plugins/poll/assets/stylesheets/desktop/poll.scss create mode 100644 plugins/poll/assets/stylesheets/mobile/poll.scss diff --git a/plugins/poll/assets/javascripts/discourse/templates/poll.hbs b/plugins/poll/assets/javascripts/discourse/templates/poll.hbs index 69662d4729..4d6b3bae16 100644 --- a/plugins/poll/assets/javascripts/discourse/templates/poll.hbs +++ b/plugins/poll/assets/javascripts/discourse/templates/poll.hbs @@ -1,4 +1,19 @@
+
+ {{#if showingResults}} + {{#if isNumber}} + {{poll-results-number poll=poll}} + {{else}} + {{poll-results-standard poll=poll}} + {{/if}} + {{else}} +
    + {{#each option in poll.options}} + {{poll-option option=option color=poll.color background=poll.background toggle="toggleOption"}} + {{/each}} +
+ {{/if}} +

{{poll.voters}} @@ -15,21 +30,6 @@ {{/if}} {{/if}}

-
- {{#if showingResults}} - {{#if isNumber}} - {{poll-results-number poll=poll}} - {{else}} - {{poll-results-standard poll=poll}} - {{/if}} - {{else}} -
    - {{#each option in poll.options}} - {{poll-option option=option color=poll.color background=poll.background toggle="toggleOption"}} - {{/each}} -
- {{/if}} -
diff --git a/plugins/poll/assets/javascripts/poll_dialect.js b/plugins/poll/assets/javascripts/poll_dialect.js index 99bafe65fd..d6eb5bf718 100644 --- a/plugins/poll/assets/javascripts/poll_dialect.js +++ b/plugins/poll/assets/javascripts/poll_dialect.js @@ -107,7 +107,11 @@ var result = ["div", attributes], poll = ["div"]; - // 1 - POLL INFO + // 1 - POLL CONTAINER + var container = ["div", { "class": "poll-container" }].concat(contents); + poll.push(container); + + // 2 - POLL INFO var info = ["div", { "class": "poll-info" }]; // # of voters @@ -148,10 +152,6 @@ poll.push(info); - // 2 - POLL CONTAINER - var container = ["div", { "class": "poll-container" }].concat(contents); - poll.push(container); - // 3 - BUTTONS var buttons = ["div", { "class": "poll-buttons" }]; diff --git a/plugins/poll/assets/stylesheets/poll.scss b/plugins/poll/assets/stylesheets/common/poll.scss similarity index 86% rename from plugins/poll/assets/stylesheets/poll.scss rename to plugins/poll/assets/stylesheets/common/poll.scss index cfc85c8f75..e78fdad11e 100644 --- a/plugins/poll/assets/stylesheets/poll.scss +++ b/plugins/poll/assets/stylesheets/common/poll.scss @@ -7,10 +7,6 @@ $option-shadow: dark-light-diff($option-background, $primary, 10%, -10%); div.poll { - display: table; - border: 1px solid $border-color; - width: 500px; - ul, ol { margin: 0; padding: 0; @@ -65,31 +61,21 @@ div.poll { .poll-info { color: $text-color; - width: 150px; - display: table-cell; text-align: center; vertical-align: middle; - border-right: 1px solid $border-color; - - p { - margin: 40px 20px; - } .info-number { font-size: 3.5em; } .info-text { - display: block; font-size: 1.7em; } } .poll-container { - display: table-cell; vertical-align: middle; padding: 10px; - width: 330px; span { font-size: 2em; @@ -97,16 +83,11 @@ div.poll { } .poll-buttons { - border-top: 1px solid $border-color; padding: 10px; button { float: none; } - - .toggle-status { - float: right; - } } .results { diff --git a/plugins/poll/assets/stylesheets/desktop/poll.scss b/plugins/poll/assets/stylesheets/desktop/poll.scss new file mode 100644 index 0000000000..3391016ff9 --- /dev/null +++ b/plugins/poll/assets/stylesheets/desktop/poll.scss @@ -0,0 +1,34 @@ +div.poll { + display: table; + border: 1px solid $border-color; + width: 500px; + max-width: 500px; + + .poll-info { + width: 150px; + display: table-cell; + border-left: 1px solid $border-color; + + p { + margin: 40px 20px; + } + + .info-text { + display: block; + } + } + + .poll-container { + display: table-cell; + width: 330px; + max-width: 330px; + } + + .poll-buttons { + border-top: 1px solid $border-color; + + .toggle-status { + float: right; + } + } +} diff --git a/plugins/poll/assets/stylesheets/mobile/poll.scss b/plugins/poll/assets/stylesheets/mobile/poll.scss new file mode 100644 index 0000000000..c574f4e4d1 --- /dev/null +++ b/plugins/poll/assets/stylesheets/mobile/poll.scss @@ -0,0 +1,7 @@ +div.poll { + .poll-buttons { + button { + margin: 3px 0; + } + } +} diff --git a/plugins/poll/plugin.rb b/plugins/poll/plugin.rb index ebf12d7ad0..ead1b6122d 100644 --- a/plugins/poll/plugin.rb +++ b/plugins/poll/plugin.rb @@ -4,7 +4,10 @@ # authors: Vikhyat Korrapati (vikhyat), Régis Hanol (zogstrip) # url: https://github.com/discourse/discourse/tree/master/plugins/poll -register_asset "stylesheets/poll.scss" +register_asset "stylesheets/common/poll.scss" +register_asset "stylesheets/desktop/poll.scss", :desktop +register_asset "stylesheets/mobile/poll.scss", :mobile + register_asset "javascripts/poll_dialect.js", :server_side PLUGIN_NAME ||= "discourse_poll".freeze From 53c85662c621ad670ae05c4a052baaf370acb099 Mon Sep 17 00:00:00 2001 From: Allen Hancock Date: Thu, 7 May 2015 13:44:27 -0700 Subject: [PATCH 017/103] A red meh icon is less ambiguous than a red-smile Builds on https://meta.discourse.org/t/why-a-frowny-face-on-admin-version/27895/ --- app/assets/javascripts/admin/templates/version-checks.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/templates/version-checks.hbs b/app/assets/javascripts/admin/templates/version-checks.hbs index 5a66cdb15f..fdc5c79946 100644 --- a/app/assets/javascripts/admin/templates/version-checks.hbs +++ b/app/assets/javascripts/admin/templates/version-checks.hbs @@ -48,7 +48,7 @@ {{else}} {{#if versionCheck.behindByOneVersion}} - {{fa-icon "smile-o"}} + {{fa-icon "meh-o"}} {{else}} {{fa-icon "frown-o"}} {{/if}} From ffeab82947c42493d507f95afa7292fbcd207c87 Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Thu, 7 May 2015 17:08:07 -0400 Subject: [PATCH 018/103] FIX: reset message field of flag form after submitting flag --- app/assets/javascripts/discourse/controllers/flag.js.es6 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/javascripts/discourse/controllers/flag.js.es6 b/app/assets/javascripts/discourse/controllers/flag.js.es6 index 4691318c29..0a24d0d280 100644 --- a/app/assets/javascripts/discourse/controllers/flag.js.es6 +++ b/app/assets/javascripts/discourse/controllers/flag.js.es6 @@ -84,6 +84,9 @@ export default ObjectController.extend(ModalFunctionality, { postAction.act(this.get('model'), params).then(function() { self.send('closeModal'); + if (params.message) { + self.set('message', ''); + } }, function(errors) { self.send('closeModal'); if (errors && errors.responseText) { From 46606cd818d49bafb14522418cfc1533a73bcdb2 Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Thu, 7 May 2015 17:31:36 -0400 Subject: [PATCH 019/103] FIX: missing aria-label on X of share modal --- app/assets/javascripts/discourse/templates/share.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/templates/share.hbs b/app/assets/javascripts/discourse/templates/share.hbs index 2270c37785..5f4c00751a 100644 --- a/app/assets/javascripts/discourse/templates/share.hbs +++ b/app/assets/javascripts/discourse/templates/share.hbs @@ -15,6 +15,6 @@ {{/each}} {{/if}} From c2ffe255c30c2d86fd871f8a7f29caf2c3cef272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Fri, 8 May 2015 11:13:32 +0200 Subject: [PATCH 020/103] FIX: add borders on polls on mobile --- plugins/poll/assets/stylesheets/common/poll.scss | 4 ++-- plugins/poll/assets/stylesheets/desktop/poll.scss | 2 +- plugins/poll/assets/stylesheets/mobile/poll.scss | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/poll/assets/stylesheets/common/poll.scss b/plugins/poll/assets/stylesheets/common/poll.scss index e78fdad11e..0953710582 100644 --- a/plugins/poll/assets/stylesheets/common/poll.scss +++ b/plugins/poll/assets/stylesheets/common/poll.scss @@ -7,6 +7,8 @@ $option-shadow: dark-light-diff($option-background, $primary, 10%, -10%); div.poll { + border: 1px solid $border-color; + ul, ol { margin: 0; padding: 0; @@ -83,8 +85,6 @@ div.poll { } .poll-buttons { - padding: 10px; - button { float: none; } diff --git a/plugins/poll/assets/stylesheets/desktop/poll.scss b/plugins/poll/assets/stylesheets/desktop/poll.scss index 3391016ff9..e875c29a03 100644 --- a/plugins/poll/assets/stylesheets/desktop/poll.scss +++ b/plugins/poll/assets/stylesheets/desktop/poll.scss @@ -1,6 +1,5 @@ div.poll { display: table; - border: 1px solid $border-color; width: 500px; max-width: 500px; @@ -26,6 +25,7 @@ div.poll { .poll-buttons { border-top: 1px solid $border-color; + padding: 10px; .toggle-status { float: right; diff --git a/plugins/poll/assets/stylesheets/mobile/poll.scss b/plugins/poll/assets/stylesheets/mobile/poll.scss index c574f4e4d1..1dc4c95caa 100644 --- a/plugins/poll/assets/stylesheets/mobile/poll.scss +++ b/plugins/poll/assets/stylesheets/mobile/poll.scss @@ -1,7 +1,9 @@ div.poll { .poll-buttons { + padding: 0 5px 5px 5px; + button { - margin: 3px 0; + margin: 4px 2px; } } } From 88135e5b22ed259e9f463049a05f9725245f3796 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Fri, 8 May 2015 18:03:36 +0530 Subject: [PATCH 021/103] FIX: fetch YouTube video title via oEmbed --- plugins/lazyYT/assets/javascripts/lazyYT.js | 15 +++++++-------- plugins/lazyYT/plugin.rb | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/plugins/lazyYT/assets/javascripts/lazyYT.js b/plugins/lazyYT/assets/javascripts/lazyYT.js index 498910cdf2..1f2cc9068f 100644 --- a/plugins/lazyYT/assets/javascripts/lazyYT.js +++ b/plugins/lazyYT/assets/javascripts/lazyYT.js @@ -16,11 +16,11 @@ height = $el.data('height'), ratio = ($el.data('ratio')) ? $el.data('ratio') : settings.default_ratio, id = $el.data('youtube-id'), + title = $el.data('youtube-title'), padding_bottom, innerHtml = [], $thumb, thumb_img, - loading_text = $el.text() ? $el.text() : settings.loading_text, youtube_parameters = $el.data('parameters') || ''; ratio = ratio.split(":"); @@ -64,8 +64,12 @@ innerHtml.push('
'); innerHtml.push(''); // .html5-title-text-wrapper @@ -102,15 +106,10 @@ } }); - $.getJSON('https://gdata.youtube.com/feeds/api/videos/' + id + '?v=2&alt=json', function (data) { - $el.find('#lazyYT-title-' + id).text(data.entry.title.$t); - }); - } $.fn.lazyYT = function (newSettings) { var defaultSettings = { - loading_text: 'Loading...', default_ratio: '16:9', callback: null, // ToDO execute callback if given container_class: 'lazyYT-container' diff --git a/plugins/lazyYT/plugin.rb b/plugins/lazyYT/plugin.rb index cf02d90882..7a9b8fc2a2 100644 --- a/plugins/lazyYT/plugin.rb +++ b/plugins/lazyYT/plugin.rb @@ -18,7 +18,7 @@ class Onebox::Engine::YoutubeOnebox def to_html if video_id # Put in the LazyYT div instead of the iframe - "
" + "
" else super end From 4da6124fa5ded8289742ae16ce72ea574533c5b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Fri, 8 May 2015 16:42:55 +0200 Subject: [PATCH 022/103] update onebox to latest --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9542962a0c..ac38899857 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -271,7 +271,7 @@ GEM omniauth-twitter (1.0.1) multi_json (~> 1.3) omniauth-oauth (~> 1.0) - onebox (1.5.17) + onebox (1.5.18) moneta (~> 0.7) multi_json (~> 1.7) mustache (~> 0.99) From 0ded6434df15b773afd8ba447d7d9e23465c0f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Fri, 8 May 2015 19:17:09 +0200 Subject: [PATCH 023/103] FIX: migrate_old_polls should properly identify olds polls at the end of the post --- plugins/poll/lib/tasks/migrate_old_polls.rake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/poll/lib/tasks/migrate_old_polls.rake b/plugins/poll/lib/tasks/migrate_old_polls.rake index d1422cc1fd..6a3ba5982f 100644 --- a/plugins/poll/lib/tasks/migrate_old_polls.rake +++ b/plugins/poll/lib/tasks/migrate_old_polls.rake @@ -14,13 +14,12 @@ task "poll:migrate_old_polls" => :environment do # go back in time Timecop.freeze(post.created_at + 1.minute) do # fix the RAW when needed + post.raw << "\n\n" if post.raw !~ /\[poll\]/ lists = /^[ ]*- .+?$\n\n/m.match(post.raw) next if lists.blank? || lists.length == 0 first_list = lists[0] post.raw = post.raw.sub(first_list, "\n[poll]\n#{first_list.strip}\n[/poll]\n") - else - post.raw = post.raw + " " end # save the poll post.save From 597dc2f0b6c0ce336647b8dc964059ab4668d385 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Fri, 8 May 2015 22:50:31 +0530 Subject: [PATCH 024/103] FIX: show youtube URL if title is undefined --- plugins/lazyYT/assets/javascripts/lazyYT.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lazyYT/assets/javascripts/lazyYT.js b/plugins/lazyYT/assets/javascripts/lazyYT.js index 1f2cc9068f..7af4f82587 100644 --- a/plugins/lazyYT/assets/javascripts/lazyYT.js +++ b/plugins/lazyYT/assets/javascripts/lazyYT.js @@ -65,7 +65,7 @@ innerHtml.push('
'); innerHtml.push('
'); innerHtml.push(''); - if (title === null || title === '') { + if (title === undefined || title === null || title === '') { innerHtml.push('https://www.youtube.com/watch?v=' + id); } else { innerHtml.push(title); From 6cc092d54cb5504e88bad2d685fbf6e9bc612eef Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Wed, 6 May 2015 18:12:35 +0530 Subject: [PATCH 025/103] FEATURE: support category/subcategory name in new-topic route --- .../discourse/controllers/composer.js.es6 | 17 +++++++++++++++++ .../discourse/mixins/open_composer.js | 3 ++- .../discourse/routes/application.js.es6 | 4 ++-- .../discourse/routes/new-topic.js.es6 | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index 65df35cae1..bd8316c845 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -441,6 +441,23 @@ export default DiscourseController.extend({ if (opts.topicCategoryId) { this.set('model.categoryId', opts.topicCategoryId); + } else if (opts.topicCategory) { + const splitCategory = opts.topicCategory.split("/"); + let category; + + if (!splitCategory[1]) { + category = this.site.get('categories').findProperty('nameLower', splitCategory[0].toLowerCase()); + } else { + const categories = Discourse.Category.list(); + const mainCategory = categories.findProperty('nameLower', splitCategory[0].toLowerCase()); + category = categories.find(function(item) { + return item && item.get('nameLower') === splitCategory[1].toLowerCase() && item.get('parent_category_id') === mainCategory.id; + }); + } + + if (category) { + this.set('model.categoryId', category.get('id')); + } } if (opts.topicBody) { diff --git a/app/assets/javascripts/discourse/mixins/open_composer.js b/app/assets/javascripts/discourse/mixins/open_composer.js index 64a79f7965..8e1906ba93 100644 --- a/app/assets/javascripts/discourse/mixins/open_composer.js +++ b/app/assets/javascripts/discourse/mixins/open_composer.js @@ -17,12 +17,13 @@ Discourse.OpenComposer = Em.Mixin.create({ }); }, - openComposerWithParams: function(controller, title, body, category_id) { + openComposerWithParams: function(controller, title, body, category_id, category) { this.controllerFor('composer').open({ action: Discourse.Composer.CREATE_TOPIC, topicTitle: title, topicBody: body, topicCategoryId: category_id, + topicCategory: category, draftKey: controller.get('draft_key'), draftSequence: controller.get('draft_sequence') }); diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6 index 4e6a61e1c0..22f97dc2c5 100644 --- a/app/assets/javascripts/discourse/routes/application.js.es6 +++ b/app/assets/javascripts/discourse/routes/application.js.es6 @@ -148,8 +148,8 @@ const ApplicationRoute = Discourse.Route.extend(Discourse.OpenComposer, { this.render(w, {into: 'modal/topic-bulk-actions', outlet: 'bulkOutlet', controller: factory ? controllerName : 'topic-bulk-actions'}); }, - createNewTopicViaParams: function(title, body, category_id) { - this.openComposerWithParams(this.controllerFor('discovery/topics'), title, body, category_id); + createNewTopicViaParams: function(title, body, category_id, category) { + this.openComposerWithParams(this.controllerFor('discovery/topics'), title, body, category_id, category); } }, diff --git a/app/assets/javascripts/discourse/routes/new-topic.js.es6 b/app/assets/javascripts/discourse/routes/new-topic.js.es6 index f09dcae028..4ce26ba279 100644 --- a/app/assets/javascripts/discourse/routes/new-topic.js.es6 +++ b/app/assets/javascripts/discourse/routes/new-topic.js.es6 @@ -7,7 +7,7 @@ export default Discourse.Route.extend({ if (self.controllerFor('navigation/default').get('canCreateTopic')) { // User can create topic Ember.run.next(function() { - e.send('createNewTopicViaParams', transition.queryParams.title, transition.queryParams.body, transition.queryParams.category_id); + e.send('createNewTopicViaParams', transition.queryParams.title, transition.queryParams.body, transition.queryParams.category_id, transition.queryParams.category); }); } }); From 8b876a3c2190609b8dd8f3e3e8e42b86b57c4162 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Sat, 9 May 2015 00:37:57 +0530 Subject: [PATCH 026/103] convert open-composer mixin to es6 --- ...{open_composer.js => open-composer.js.es6} | 22 +++++++------------ .../discourse/routes/application.js.es6 | 3 ++- .../routes/discovery-categories-route.js.es6 | 3 ++- .../discourse/routes/discovery.js.es6 | 3 ++- 4 files changed, 14 insertions(+), 17 deletions(-) rename app/assets/javascripts/discourse/mixins/{open_composer.js => open-composer.js.es6} (51%) diff --git a/app/assets/javascripts/discourse/mixins/open_composer.js b/app/assets/javascripts/discourse/mixins/open-composer.js.es6 similarity index 51% rename from app/assets/javascripts/discourse/mixins/open_composer.js rename to app/assets/javascripts/discourse/mixins/open-composer.js.es6 index 8e1906ba93..03516b9d8b 100644 --- a/app/assets/javascripts/discourse/mixins/open_composer.js +++ b/app/assets/javascripts/discourse/mixins/open-composer.js.es6 @@ -1,14 +1,8 @@ -/** - This mixin allows a route to open the composer +// This mixin allows a route to open the composer - @class Discourse.OpenComposer - @extends Ember.Mixin - @namespace Discourse - @module Discourse -**/ -Discourse.OpenComposer = Em.Mixin.create({ +export default Ember.Mixin.create({ - openComposer: function(controller) { + openComposer(controller) { this.controllerFor('composer').open({ categoryId: controller.get('category.id'), action: Discourse.Composer.CREATE_TOPIC, @@ -17,13 +11,13 @@ Discourse.OpenComposer = Em.Mixin.create({ }); }, - openComposerWithParams: function(controller, title, body, category_id, category) { + openComposerWithParams(controller, topicTitle, topicBody, topicCategoryId, topicCategory) { this.controllerFor('composer').open({ action: Discourse.Composer.CREATE_TOPIC, - topicTitle: title, - topicBody: body, - topicCategoryId: category_id, - topicCategory: category, + topicTitle, + topicBody, + topicCategoryId, + topicCategory, draftKey: controller.get('draft_key'), draftSequence: controller.get('draft_sequence') }); diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6 index 22f97dc2c5..17d5d824e9 100644 --- a/app/assets/javascripts/discourse/routes/application.js.es6 +++ b/app/assets/javascripts/discourse/routes/application.js.es6 @@ -1,4 +1,5 @@ import showModal from 'discourse/lib/show-modal'; +import OpenComposer from "discourse/mixins/open-composer"; function unlessReadOnly(method) { return function() { @@ -10,7 +11,7 @@ function unlessReadOnly(method) { }; } -const ApplicationRoute = Discourse.Route.extend(Discourse.OpenComposer, { +const ApplicationRoute = Discourse.Route.extend(OpenComposer, { siteTitle: Discourse.computed.setting('title'), diff --git a/app/assets/javascripts/discourse/routes/discovery-categories-route.js.es6 b/app/assets/javascripts/discourse/routes/discovery-categories-route.js.es6 index 636a646db2..c46b9b8275 100644 --- a/app/assets/javascripts/discourse/routes/discovery-categories-route.js.es6 +++ b/app/assets/javascripts/discourse/routes/discovery-categories-route.js.es6 @@ -1,7 +1,8 @@ import ShowFooter from 'discourse/mixins/show-footer'; import showModal from 'discourse/lib/show-modal'; +import OpenComposer from "discourse/mixins/open-composer"; -Discourse.DiscoveryCategoriesRoute = Discourse.Route.extend(Discourse.OpenComposer, ShowFooter, { +Discourse.DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, ShowFooter, { renderTemplate() { this.render('navigation/categories', { outlet: 'navigation-bar' }); this.render('discovery/categories', { outlet: 'list-container' }); diff --git a/app/assets/javascripts/discourse/routes/discovery.js.es6 b/app/assets/javascripts/discourse/routes/discovery.js.es6 index c12cb9a72c..572b9536bd 100644 --- a/app/assets/javascripts/discourse/routes/discovery.js.es6 +++ b/app/assets/javascripts/discourse/routes/discovery.js.es6 @@ -4,8 +4,9 @@ **/ import ShowFooter from "discourse/mixins/show-footer"; +import OpenComposer from "discourse/mixins/open-composer"; -const DiscoveryRoute = Discourse.Route.extend(Discourse.ScrollTop, Discourse.OpenComposer, ShowFooter, { +const DiscoveryRoute = Discourse.Route.extend(Discourse.ScrollTop, OpenComposer, ShowFooter, { redirect: function() { return this.redirectIfLoginRequired(); }, beforeModel: function(transition) { From c2312a427adada3c1310ad83de12c869bb0a76eb Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Sat, 9 May 2015 01:18:42 +0530 Subject: [PATCH 027/103] UX: no need to show protocol in youtube link --- plugins/lazyYT/assets/javascripts/lazyYT.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lazyYT/assets/javascripts/lazyYT.js b/plugins/lazyYT/assets/javascripts/lazyYT.js index 7af4f82587..bce0077581 100644 --- a/plugins/lazyYT/assets/javascripts/lazyYT.js +++ b/plugins/lazyYT/assets/javascripts/lazyYT.js @@ -66,7 +66,7 @@ innerHtml.push('
'); innerHtml.push(''); if (title === undefined || title === null || title === '') { - innerHtml.push('https://www.youtube.com/watch?v=' + id); + innerHtml.push('youtube.com/watch?v=' + id); } else { innerHtml.push(title); } From f355579e608395b2bb4577b4d6d269f52fabb952 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Fri, 8 May 2015 15:47:27 -0700 Subject: [PATCH 028/103] remove transparent outline on topic-progress-wrapper --- app/assets/stylesheets/desktop/topic.scss | 1 - app/assets/stylesheets/mobile/topic.scss | 1 - 2 files changed, 2 deletions(-) diff --git a/app/assets/stylesheets/desktop/topic.scss b/app/assets/stylesheets/desktop/topic.scss index 06ac6b7f91..7707ec9056 100644 --- a/app/assets/stylesheets/desktop/topic.scss +++ b/app/assets/stylesheets/desktop/topic.scss @@ -113,7 +113,6 @@ a:hover.reply-new { width: 0; bottom: 0; z-index: 500; - outline: 1px solid transparent; &.docked { position: absolute; bottom: -70px; diff --git a/app/assets/stylesheets/mobile/topic.scss b/app/assets/stylesheets/mobile/topic.scss index 313bcfcd7c..856218de87 100644 --- a/app/assets/stylesheets/mobile/topic.scss +++ b/app/assets/stylesheets/mobile/topic.scss @@ -58,7 +58,6 @@ bottom: 0; z-index: 500; margin-right: 145px; - outline: 1px solid transparent; } #topic-progress-expanded { From 7238c430181d8d73ce372ae7020f88befb428503 Mon Sep 17 00:00:00 2001 From: riking Date: Fri, 8 May 2015 19:28:04 -0700 Subject: [PATCH 029/103] SECURITY: XSS in poll errors dialog --- plugins/poll/plugin.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/poll/plugin.rb b/plugins/poll/plugin.rb index ead1b6122d..3808e0aaa5 100644 --- a/plugins/poll/plugin.rb +++ b/plugins/poll/plugin.rb @@ -220,7 +220,7 @@ after_initialize do if polls.has_key?(poll["name"]) poll["name"] == DEFAULT_POLL_NAME ? self.errors.add(:base, I18n.t("poll.multiple_polls_without_name")) : - self.errors.add(:base, I18n.t("poll.multiple_polls_with_same_name", name: poll["name"])) + self.errors.add(:base, I18n.t("poll.multiple_polls_with_same_name", name: ERB::Util.html_escape(poll["name"]))) return end @@ -228,7 +228,7 @@ after_initialize do if poll["options"].map { |o| o["id"] }.uniq.size != poll["options"].size poll["name"] == DEFAULT_POLL_NAME ? self.errors.add(:base, I18n.t("poll.default_poll_must_have_different_options")) : - self.errors.add(:base, I18n.t("poll.named_poll_must_have_different_options", name: poll["name"])) + self.errors.add(:base, I18n.t("poll.named_poll_must_have_different_options", name: ERB::Util.html_escape(poll["name"]))) return end @@ -236,7 +236,7 @@ after_initialize do if poll["options"].size < 2 poll["name"] == DEFAULT_POLL_NAME ? self.errors.add(:base, I18n.t("poll.default_poll_must_have_at_least_2_options")) : - self.errors.add(:base, I18n.t("poll.named_poll_must_have_at_least_2_options", name: poll["name"])) + self.errors.add(:base, I18n.t("poll.named_poll_must_have_at_least_2_options", name: ERB::Util.html_escape(poll["name"]))) return end @@ -244,7 +244,7 @@ after_initialize do if poll["options"].size > SiteSetting.poll_maximum_options poll["name"] == DEFAULT_POLL_NAME ? self.errors.add(:base, I18n.t("poll.default_poll_must_have_less_options", max: SiteSetting.poll_maximum_options)) : - self.errors.add(:base, I18n.t("poll.named_poll_must_have_less_options", name: poll["name"], max: SiteSetting.poll_maximum_options)) + self.errors.add(:base, I18n.t("poll.named_poll_must_have_less_options", name: ERB::Util.html_escape(poll["name"]), max: SiteSetting.poll_maximum_options)) return end From b99c3c85aa906d54bcf507066664fc39b328b9fd Mon Sep 17 00:00:00 2001 From: Qasem Hajizadeh Date: Sat, 9 May 2015 18:26:00 +0430 Subject: [PATCH 030/103] Update rtl.scss --- app/assets/stylesheets/common/base/rtl.scss | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/assets/stylesheets/common/base/rtl.scss b/app/assets/stylesheets/common/base/rtl.scss index 9a6dfeb7ed..83fb336761 100644 --- a/app/assets/stylesheets/common/base/rtl.scss +++ b/app/assets/stylesheets/common/base/rtl.scss @@ -31,3 +31,10 @@ border-left-color: transparent !important; border-right-color: $secondary !important; } +code { + direction: ltr !important; + text-aligh: left !important; +} +.pull-left { + float:right !important; +} From 5329403a713999ab5ea7b4e9b934a7fd7aeaaefc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Sun, 10 May 2015 23:12:09 +0200 Subject: [PATCH 031/103] use first part of email address as username in SFN import --- script/import_scripts/sfn.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/script/import_scripts/sfn.rb b/script/import_scripts/sfn.rb index b5178146c2..f8a14f00d9 100644 --- a/script/import_scripts/sfn.rb +++ b/script/import_scripts/sfn.rb @@ -40,7 +40,7 @@ class ImportScripts::Sfn < ImportScripts::Base @external_users = {} - CSV.foreach("/Users/zogstrip/Downloads/sfn.csv", col_sep: ";") do |row| + CSV.foreach("/Users/zogstrip/Desktop/sfn.csv", col_sep: ";") do |row| next unless @personify_id_to_contact_key.include?(row[0]) id = @personify_id_to_contact_key[row[0]] @@ -90,6 +90,7 @@ class ImportScripts::Sfn < ImportScripts::Base id: user["id"], email: email, name: full_name, + username: email.split("@")[0], bio_raw: bio, created_at: user["created_at"], post_create_action: proc do |newuser| @@ -191,13 +192,13 @@ class ImportScripts::Sfn < ImportScripts::Base "{9613BAC2-229B-4563-9E1C-35C31CDDCE2F}" => 49, # "Students", } - # def import_categories - # puts "", "importing categories..." + def import_categories + puts "", "importing categories..." - # create_categories(NEW_CATEGORIES) do |category| - # { id: category, name: category } - # end - # end + create_categories(NEW_CATEGORIES) do |category| + { id: category, name: category } + end + end def import_topics puts "", "importing topics..." From 996ab1ae1752551bb1a330df73fea287c28edcef Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 11 May 2015 10:30:22 +1000 Subject: [PATCH 032/103] FEATURE: task to find all missing local images --- lib/tasks/uploads.rake | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/lib/tasks/uploads.rake b/lib/tasks/uploads.rake index f8b8c25b9c..86c50f41b0 100644 --- a/lib/tasks/uploads.rake +++ b/lib/tasks/uploads.rake @@ -157,3 +157,52 @@ task "uploads:clean_up" => :environment do end end + + +# list all missing uploads and optimized images +task "uploads:missing" => :environment do + + public_directory = "#{Rails.root}/public" + + RailsMultisite::ConnectionManagement.each_connection do |db| + + if Discourse.store.external? + puts "This task only works for internal storages." + next + end + + + Upload.order(:id).find_each do |upload| + + # could be a remote image + next unless upload.url =~ /^\/uploads\// + + path = "#{public_directory}#{upload.url}" + bad = true + begin + bad = false if File.size(path) != 0 + rescue + # something is messed up + end + puts path if bad + end + + OptimizedImage.order(:id).find_each do |optimized_image| + + # remote? + next unless optimized_image.url =~ /^\/uploads\// + + path = "#{public_directory}#{optimized_image.url}" + + bad = true + begin + bad = false if File.size(path) != 0 + rescue + # something is messed up + end + puts path if bad + end + + end + +end From 2282869f30af41bb897c98f4be1fe155551b9d62 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 11 May 2015 12:12:37 +1000 Subject: [PATCH 033/103] fix rtl changing general styles --- app/assets/stylesheets/common/base/rtl.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/common/base/rtl.scss b/app/assets/stylesheets/common/base/rtl.scss index 83fb336761..804af0bc4b 100644 --- a/app/assets/stylesheets/common/base/rtl.scss +++ b/app/assets/stylesheets/common/base/rtl.scss @@ -31,10 +31,10 @@ border-left-color: transparent !important; border-right-color: $secondary !important; } -code { +.rtl code { direction: ltr !important; text-aligh: left !important; } -.pull-left { +.rtl .pull-left { float:right !important; } From 5e7585958ac5f341dfdf4e5da65e09d1a564032e Mon Sep 17 00:00:00 2001 From: Wladimir Braguini Domingues Date: Mon, 11 May 2015 01:07:19 -0300 Subject: [PATCH 034/103] Change Vagrantfile to default VM 1024MB of RAM Revert a commit that changed the default Vagrantfile to 2048MB of RAM https://meta.discourse.org/t/discourse-as-your-first-rails-app/5751/105 --- Vagrantfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vagrantfile b/Vagrantfile index 9702bba015..b598918036 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -17,7 +17,7 @@ Vagrant.configure("2") do |config| config.vm.provider :virtualbox do |v| # This setting gives the VM 1024MB of RAM instead of the default 384. - v.customize ["modifyvm", :id, "--memory", [ENV['DISCOURSE_VM_MEM'].to_i, 2048].max] + v.customize ["modifyvm", :id, "--memory", [ENV['DISCOURSE_VM_MEM'].to_i, 1024].max] # Who has a single core cpu these days anyways? cpu_count = 2 From 7a20ed061702847e96f28d32df4f737d8eff3dda Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Mon, 11 May 2015 10:50:24 +0530 Subject: [PATCH 035/103] FIX: rss feed should be valid --- app/views/list/list.rss.erb | 2 +- app/views/topics/show.rss.erb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/list/list.rss.erb b/app/views/list/list.rss.erb index 63684a5e82..deb5e80f02 100644 --- a/app/views/list/list.rss.erb +++ b/app/views/list/list.rss.erb @@ -11,7 +11,7 @@ <%= @topic_list.topics.first.created_at.rfc2822 %> <% @topic_list.topics.each do |topic| %> - <% topic_url = topic.relative_url -%> + <% topic_url = topic.url -%> <%= topic.title %> <%= "no-reply@example.com (@#{topic.user.username}#{" #{topic.user.name}" if (topic.user.name.present? && SiteSetting.enable_names?)})" -%> diff --git a/app/views/topics/show.rss.erb b/app/views/topics/show.rss.erb index dbfda1d2e9..03b5471ecb 100644 --- a/app/views/topics/show.rss.erb +++ b/app/views/topics/show.rss.erb @@ -1,7 +1,7 @@ - <% topic_url = @topic_view.relative_url %> + <% topic_url = @topic_view.absolute_url %> <% lang = SiteSetting.find_by_name('default_locale').try(:value) %> <% site_email = SiteSetting.find_by_name('contact_email').try(:value) %> <%= @topic_view.title %> @@ -31,7 +31,7 @@ <%= post_url %> <%= post.created_at.rfc2822 %> post-<%= post.topic_id %>-<%= post.post_number %> - <%= @topic_view.title %> + <%= @topic_view.title %> <% end %> From 8366b711764426d343cfb4efb66557583c9bbfdb Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Mon, 11 May 2015 12:06:28 +0530 Subject: [PATCH 036/103] FEATURE: check nofollow setting when showing website --- app/assets/javascripts/discourse/controllers/user.js.es6 | 4 ++++ app/assets/javascripts/discourse/templates/user/user.hbs | 6 +++++- config/site_settings.yml | 4 +++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/user.js.es6 b/app/assets/javascripts/discourse/controllers/user.js.es6 index 4a0e666cfa..512df986e1 100644 --- a/app/assets/javascripts/discourse/controllers/user.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user.js.es6 @@ -19,6 +19,10 @@ export default ObjectController.extend(CanCheckEmails, { linkWebsite: Em.computed.not('isBasic'), + removeNoFollow: function() { + return this.get('trust_level') > 2 && !this.siteSettings.tl3_links_no_follow; + }.property('trust_level'), + canSeePrivateMessages: Ember.computed.or('viewingSelf', 'currentUser.admin'), canSeeNotificationHistory: Em.computed.alias('canSeePrivateMessages'), diff --git a/app/assets/javascripts/discourse/templates/user/user.hbs b/app/assets/javascripts/discourse/templates/user/user.hbs index 973faae83e..f15a4f9e4e 100644 --- a/app/assets/javascripts/discourse/templates/user/user.hbs +++ b/app/assets/javascripts/discourse/templates/user/user.hbs @@ -71,7 +71,11 @@ {{#if websiteName}} {{fa-icon "globe"}} {{#if linkWebsite}} - {{websiteName}} + {{#if removeNoFollow}} + {{websiteName}} + {{else}} + {{websiteName}} + {{/if}} {{else}} {{websiteName}} {{/if}} diff --git a/config/site_settings.yml b/config/site_settings.yml index 30270d0201..8bb55f956a 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -611,7 +611,9 @@ trust: tl3_requires_likes_received: default: 20 min: 0 - tl3_links_no_follow: false + tl3_links_no_follow: + default: false + client: true security: use_https: false From f180aba492f7263857a3efdf71c247bc721cf8d7 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 11 May 2015 17:48:54 +1000 Subject: [PATCH 037/103] stop random hostname for anon --- app/services/anonymous_shadow_creator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/anonymous_shadow_creator.rb b/app/services/anonymous_shadow_creator.rb index 3441455d8c..2b9729dd60 100644 --- a/app/services/anonymous_shadow_creator.rb +++ b/app/services/anonymous_shadow_creator.rb @@ -33,7 +33,7 @@ class AnonymousShadowCreator User.transaction do shadow = User.create!( password: SecureRandom.hex, - email: "#{SecureRandom.hex}@#{SecureRandom.hex}.com", + email: "#{SecureRandom.hex}@anon.#{Discourse.current_hostname}.com", name: "", username: UserNameSuggester.suggest(I18n.t(:anonymous).downcase), active: true, From 6bd15dd86d78582695e21a76e4dc465fe436daba Mon Sep 17 00:00:00 2001 From: Qasem Hajizadeh Date: Mon, 11 May 2015 12:22:30 +0430 Subject: [PATCH 038/103] Add .rtl for css tags Im added .rtl to front of tags @SamSaffron --- app/assets/stylesheets/common/base/rtl.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/common/base/rtl.scss b/app/assets/stylesheets/common/base/rtl.scss index 83fb336761..804af0bc4b 100644 --- a/app/assets/stylesheets/common/base/rtl.scss +++ b/app/assets/stylesheets/common/base/rtl.scss @@ -31,10 +31,10 @@ border-left-color: transparent !important; border-right-color: $secondary !important; } -code { +.rtl code { direction: ltr !important; text-aligh: left !important; } -.pull-left { +.rtl .pull-left { float:right !important; } From 3d6cfc6421b0dd487728aef006c300097af5d980 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 11 May 2015 18:05:18 +1000 Subject: [PATCH 039/103] fix typo --- app/services/anonymous_shadow_creator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/anonymous_shadow_creator.rb b/app/services/anonymous_shadow_creator.rb index 2b9729dd60..f2abd9e1b1 100644 --- a/app/services/anonymous_shadow_creator.rb +++ b/app/services/anonymous_shadow_creator.rb @@ -33,7 +33,7 @@ class AnonymousShadowCreator User.transaction do shadow = User.create!( password: SecureRandom.hex, - email: "#{SecureRandom.hex}@anon.#{Discourse.current_hostname}.com", + email: "#{SecureRandom.hex}@anon.#{Discourse.current_hostname}", name: "", username: UserNameSuggester.suggest(I18n.t(:anonymous).downcase), active: true, From fc30b771cf2ad6b848eae529a16c2236e5bf99a9 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Mon, 11 May 2015 13:56:21 +0530 Subject: [PATCH 040/103] FIX: reply count is off by one --- app/controllers/embed_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/embed_controller.rb b/app/controllers/embed_controller.rb index 4eaaa4c378..033d47a18a 100644 --- a/app/controllers/embed_controller.rb +++ b/app/controllers/embed_controller.rb @@ -21,7 +21,7 @@ class EmbedController < ApplicationController @second_post_url = "#{@topic_view.topic.url}/2" if @topic_view @posts_left = 0 if @topic_view && @topic_view.posts.size == SiteSetting.embed_post_limit - @posts_left = @topic_view.topic.posts_count - SiteSetting.embed_post_limit + @posts_left = @topic_view.topic.posts_count - SiteSetting.embed_post_limit - 1 end else Jobs.enqueue(:retrieve_topic, user_id: current_user.try(:id), embed_url: embed_url) From ca89d169467120aaaacf7d833cf8162552b2da55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 11 May 2015 12:59:50 +0200 Subject: [PATCH 041/103] FEATURE: new 'uploads:regenerate_missing_optimized' images rake task --- lib/tasks/uploads.rake | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/lib/tasks/uploads.rake b/lib/tasks/uploads.rake index 86c50f41b0..b709c98feb 100644 --- a/lib/tasks/uploads.rake +++ b/lib/tasks/uploads.rake @@ -206,3 +206,47 @@ task "uploads:missing" => :environment do end end + +# regenerate missing optimized images +task "uploads:regenerate_missing_optimized" => :environment do + puts "Regenerating missing optimized images for '#{RailsMultisite::ConnectionManagement.current_db}'..." + + if Discourse.store.external? + puts "This task only works for internal storages." + return + end + + public_directory = "#{Rails.root}/public" + missing_uploads = Set.new + + OptimizedImage.includes(:upload) + .where("LENGTH(COALESCE(url, '')) > 0") + .where("width > 0 AND height > 0") + .order(:id) + .find_each do |optimized_image| + + thumbnail = "#{public_directory}#{optimized_image.url}" + upload = "#{public_directory}#{optimized_image.upload.url}" + + if !File.exists?(thumbnail) || File.size(thumbnail) <= 0 + if File.exists?(upload) && File.size(upload) > 0 + FileUtils.mkdir_p(File.dirname(thumbnail)) + OptimizedImage.resize(upload, thumbnail, optimized_image.width, optimized_image.height) + putc "#" + else + missing_uploads << upload + putc "X" + end + else + putc "." + end + end + + puts "", "Done" + + if missing_uploads.size > 0 + puts "Missing uploads:" + missing_uploads.sort.each { |u| puts u } + end + +end From 27a9b5ee13b62bd4f363cce4152237a0b91b95da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 11 May 2015 15:41:52 +0200 Subject: [PATCH 042/103] only deal with local uploads --- lib/tasks/uploads.rake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/tasks/uploads.rake b/lib/tasks/uploads.rake index b709c98feb..b8958c9183 100644 --- a/lib/tasks/uploads.rake +++ b/lib/tasks/uploads.rake @@ -225,6 +225,9 @@ task "uploads:regenerate_missing_optimized" => :environment do .order(:id) .find_each do |optimized_image| + next unless optimized_image.url =~ /^\/uploads\// + next unless optimized_image.upload.url =~ /^\/uploads\// + thumbnail = "#{public_directory}#{optimized_image.url}" upload = "#{public_directory}#{optimized_image.upload.url}" From 6d83526bf1fe027c3ce74da61f9d699033c9c6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 11 May 2015 16:19:16 +0200 Subject: [PATCH 043/103] add support for multisite to the 'uploads:regenerate_missing_optimized' rake task --- lib/tasks/uploads.rake | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/tasks/uploads.rake b/lib/tasks/uploads.rake index b8958c9183..99a3c7aa51 100644 --- a/lib/tasks/uploads.rake +++ b/lib/tasks/uploads.rake @@ -209,6 +209,14 @@ end # regenerate missing optimized images task "uploads:regenerate_missing_optimized" => :environment do + ENV["RAILS_DB"] ? regenerate_missing_optimized : regenerate_missing_optimized_all_sites +end + +def regenerate_missing_optimized_all_sites + RailsMultisite::ConnectionManagement.each_connection { regenerate_missing_optimized } +end + +def regenerate_missing_optimized puts "Regenerating missing optimized images for '#{RailsMultisite::ConnectionManagement.current_db}'..." if Discourse.store.external? @@ -251,5 +259,4 @@ task "uploads:regenerate_missing_optimized" => :environment do puts "Missing uploads:" missing_uploads.sort.each { |u| puts u } end - end From 48f4589c6f35f69042c1905a6101b24d6a025b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 11 May 2015 17:03:48 +0200 Subject: [PATCH 044/103] try to fix missing downloads by re-downloading them --- lib/tasks/uploads.rake | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/tasks/uploads.rake b/lib/tasks/uploads.rake index 99a3c7aa51..a4aa29ac1e 100644 --- a/lib/tasks/uploads.rake +++ b/lib/tasks/uploads.rake @@ -240,6 +240,17 @@ def regenerate_missing_optimized upload = "#{public_directory}#{optimized_image.upload.url}" if !File.exists?(thumbnail) || File.size(thumbnail) <= 0 + # make sure the original image exists locally + if (!File.exists?(upload) || File.size(upload) <= 0) && optimized_image.upload.origin.present? + # try to fix it by redownloading it + begin + downloaded = FileHelper.download(optimized_image.upload.origin, SiteSetting.max_image_size_kb.kilobytes, "discourse-missing", true) rescue nil + Discourse.store.store_upload(downloaded, optimized_image.upload) + ensure + downloaded.try(:close!) if downloaded.respond_to?(:close!) + end + end + if File.exists?(upload) && File.size(upload) > 0 FileUtils.mkdir_p(File.dirname(thumbnail)) OptimizedImage.resize(upload, thumbnail, optimized_image.width, optimized_image.height) From b3b4fd21ed1a47a35811b06d085f23ca1fb8842f Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Tue, 28 Apr 2015 17:05:06 -0400 Subject: [PATCH 045/103] Broken WIP --- .../admin/templates/email_preview_digest.hbs | 4 +- .../admin/templates/flags-list.hbs | 2 +- .../admin/templates/logs/screened_emails.hbs | 4 +- .../templates/logs/screened_ip_addresses.hbs | 4 +- .../admin/templates/logs/screened_urls.hbs | 4 +- .../templates/logs/staff_action_logs.hbs | 4 +- .../javascripts/admin/templates/reports.hbs | 4 +- .../admin/templates/user_badges.hbs | 4 +- .../admin/templates/users-list-show.hbs | 8 +- .../activity-filter.js.es6 | 0 .../category-chooser.js.es6 | 4 +- .../{views => components}/combo-box.js.es6 | 5 +- .../conditional-loading-spinner.js.es6 | 2 +- .../discourse/components/count-i18n.js.es6 | 8 + .../discourse/components/d-button.js.es6 | 2 +- .../discourse/components/input-tip.js.es6 | 17 + .../popup-input-tip.js.es6} | 31 +- .../discourse/helpers/count-i18n.js.es6 | 17 - .../discourse/helpers/custom-html.js.es6 | 2 +- .../discourse/helpers/loading-spinner.es6 | 24 +- .../discourse/helpers/plugin-outlet.js.es6 | 3 + .../discourse/helpers/register-unbound.js.es6 | 7 +- .../initializers/view-helpers.js.es6 | 25 - .../discourse/templates/badges/show.hbs | 2 +- .../templates/components/basic-topic-list.hbs | 4 +- .../templates/components/category-drop.hbs | 2 +- .../templates/components/ip-lookup.hbs | 4 +- .../discourse/templates/composer.hbs | 6 +- .../discourse/templates/discovery.hbs | 2 +- .../discourse/templates/discovery/topics.hbs | 4 +- .../discourse/templates/exception.hbs | 2 +- .../mobile/components/basic-topic-list.hbs | 4 +- .../templates/mobile/discovery/topics.hbs | 4 +- .../templates/modal/bulk_change_category.hbs | 4 +- .../templates/modal/create-account.hbs | 4 +- .../templates/modal/feature-topic.hbs | 20 +- .../discourse/templates/modal/history.hbs | 4 +- .../discourse/templates/modal/login.hbs | 2 +- .../templates/modal/post-enqueued.hbs | 2 +- .../discourse/templates/notifications.hbs | 4 +- .../discourse/templates/popup_input_tip.hbs | 2 - .../javascripts/discourse/templates/quote.hbs | 10 +- .../discourse/templates/selected_posts.hbs | 2 +- .../javascripts/discourse/templates/topic.hbs | 14 +- .../discourse/templates/user/invited.hbs | 2 +- .../templates/user/notifications.hbs | 4 +- .../javascripts/discourse/templates/users.hbs | 6 +- .../discourse/views/input-tip.js.es6 | 17 - .../javascripts/discourse/views/view.js.es6 | 16 +- app/assets/javascripts/ember_include.js.erb | 1 + app/assets/javascripts/main_include.js | 2 +- test/javascripts/views/view-test.js.es6 | 34 - .../assets/javascripts/development/ember.js | 14386 +++++++++------- .../javascripts/ember-template-compiler.js | 7193 ++++++++ vendor/assets/javascripts/production/ember.js | 13948 +++++++++------ 55 files changed, 24009 insertions(+), 11887 deletions(-) rename app/assets/javascripts/discourse/{views => components}/activity-filter.js.es6 (100%) rename app/assets/javascripts/discourse/{views => components}/category-chooser.js.es6 (96%) rename app/assets/javascripts/discourse/{views => components}/combo-box.js.es6 (92%) create mode 100644 app/assets/javascripts/discourse/components/count-i18n.js.es6 create mode 100644 app/assets/javascripts/discourse/components/input-tip.js.es6 rename app/assets/javascripts/discourse/{views/popup_input_tip_view.js => components/popup-input-tip.js.es6} (63%) delete mode 100644 app/assets/javascripts/discourse/helpers/count-i18n.js.es6 delete mode 100644 app/assets/javascripts/discourse/initializers/view-helpers.js.es6 delete mode 100644 app/assets/javascripts/discourse/templates/popup_input_tip.hbs delete mode 100644 app/assets/javascripts/discourse/views/input-tip.js.es6 delete mode 100644 test/javascripts/views/view-test.js.es6 create mode 100644 vendor/assets/javascripts/ember-template-compiler.js diff --git a/app/assets/javascripts/admin/templates/email_preview_digest.hbs b/app/assets/javascripts/admin/templates/email_preview_digest.hbs index d5f3f932b2..7670d6194b 100644 --- a/app/assets/javascripts/admin/templates/email_preview_digest.hbs +++ b/app/assets/javascripts/admin/templates/email_preview_digest.hbs @@ -18,10 +18,10 @@
-{{#loading-spinner condition=loading}} +{{#conditional-loading-spinner condition=loading}} {{#if showHtml}} {{{html_content}}} {{else}}
{{{text_content}}}
{{/if}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/admin/templates/flags-list.hbs b/app/assets/javascripts/admin/templates/flags-list.hbs index 6285d9e938..e001e92ae8 100644 --- a/app/assets/javascripts/admin/templates/flags-list.hbs +++ b/app/assets/javascripts/admin/templates/flags-list.hbs @@ -147,7 +147,7 @@ - {{loading-spinner condition=view.loading}} + {{conditional-loading-spinner condition=view.loading}} {{else}}

{{i18n 'admin.flags.no_results'}}

{{/if}} diff --git a/app/assets/javascripts/admin/templates/logs/screened_emails.hbs b/app/assets/javascripts/admin/templates/logs/screened_emails.hbs index 506ede054d..fba64d367d 100644 --- a/app/assets/javascripts/admin/templates/logs/screened_emails.hbs +++ b/app/assets/javascripts/admin/templates/logs/screened_emails.hbs @@ -4,7 +4,7 @@


-{{#loading-spinner condition=loading}} +{{#conditional-loading-spinner condition=loading}} {{#if model.length}}
@@ -25,4 +25,4 @@ {{else}} {{i18n 'search.no_results'}} {{/if}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.hbs b/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.hbs index 27fa423711..515c22a3a0 100644 --- a/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.hbs +++ b/app/assets/javascripts/admin/templates/logs/screened_ip_addresses.hbs @@ -7,7 +7,7 @@ {{screened-ip-address-form action="recordAdded"}}
-{{#loading-spinner condition=loading}} +{{#conditional-loading-spinner condition=loading}} {{#if model.length}}
@@ -27,4 +27,4 @@ {{else}} {{i18n 'search.no_results'}} {{/if}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/admin/templates/logs/screened_urls.hbs b/app/assets/javascripts/admin/templates/logs/screened_urls.hbs index aba722a9c7..4fa38f1170 100644 --- a/app/assets/javascripts/admin/templates/logs/screened_urls.hbs +++ b/app/assets/javascripts/admin/templates/logs/screened_urls.hbs @@ -4,7 +4,7 @@


-{{#loading-spinner condition=loading}} +{{#conditional-loading-spinner condition=loading}} {{#if model.length}}
@@ -21,4 +21,4 @@ {{else}} {{i18n 'search.no_results'}} {{/if}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/admin/templates/logs/staff_action_logs.hbs b/app/assets/javascripts/admin/templates/logs/staff_action_logs.hbs index c5ce3aa46e..a90154cf74 100644 --- a/app/assets/javascripts/admin/templates/logs/staff_action_logs.hbs +++ b/app/assets/javascripts/admin/templates/logs/staff_action_logs.hbs @@ -48,11 +48,11 @@
- {{#loading-spinner condition=loading}} + {{#conditional-loading-spinner condition=loading}} {{#if model.length}} {{view "staff-action-logs-list" content=controller}} {{else}} {{i18n 'search.no_results'}} {{/if}} - {{/loading-spinner}} + {{/conditional-loading-spinner}}
diff --git a/app/assets/javascripts/admin/templates/reports.hbs b/app/assets/javascripts/admin/templates/reports.hbs index e4fdc87cbf..0bc26a8739 100644 --- a/app/assets/javascripts/admin/templates/reports.hbs +++ b/app/assets/javascripts/admin/templates/reports.hbs @@ -20,7 +20,7 @@ {{/if}}
-{{#loading-spinner condition=refreshing}} +{{#conditional-loading-spinner condition=refreshing}} @@ -43,4 +43,4 @@ {{/each}}
{{xaxis}}
-{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/admin/templates/user_badges.hbs b/app/assets/javascripts/admin/templates/user_badges.hbs index 5d55a2d0b5..c6e9a86b6d 100644 --- a/app/assets/javascripts/admin/templates/user_badges.hbs +++ b/app/assets/javascripts/admin/templates/user_badges.hbs @@ -6,7 +6,7 @@
-{{#loading-spinner condition=loading}} +{{#conditional-loading-spinner condition=loading}}

{{i18n 'admin.badges.grant_badge'}}


@@ -67,4 +67,4 @@ {{/each}}
-{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/admin/templates/users-list-show.hbs b/app/assets/javascripts/admin/templates/users-list-show.hbs index 750685509a..f31b449127 100644 --- a/app/assets/javascripts/admin/templates/users-list-show.hbs +++ b/app/assets/javascripts/admin/templates/users-list-show.hbs @@ -1,7 +1,7 @@ {{#if hasSelection}}
- - + +
{{/if}} @@ -19,7 +19,7 @@ {{/unless}}
-{{#loading-spinner condition=refreshing}} +{{#conditional-loading-spinner condition=refreshing}} {{#if model}} @@ -81,4 +81,4 @@ {{else}}

{{i18n 'search.no_results'}}

{{/if}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/discourse/views/activity-filter.js.es6 b/app/assets/javascripts/discourse/components/activity-filter.js.es6 similarity index 100% rename from app/assets/javascripts/discourse/views/activity-filter.js.es6 rename to app/assets/javascripts/discourse/components/activity-filter.js.es6 diff --git a/app/assets/javascripts/discourse/views/category-chooser.js.es6 b/app/assets/javascripts/discourse/components/category-chooser.js.es6 similarity index 96% rename from app/assets/javascripts/discourse/views/category-chooser.js.es6 rename to app/assets/javascripts/discourse/components/category-chooser.js.es6 index 9f6fc1674f..ed2b8a55ea 100644 --- a/app/assets/javascripts/discourse/views/category-chooser.js.es6 +++ b/app/assets/javascripts/discourse/components/category-chooser.js.es6 @@ -1,4 +1,4 @@ -import ComboboxView from 'discourse/views/combo-box'; +import ComboboxView from 'discourse/components/combo-box'; import { categoryBadgeHTML } from 'discourse/helpers/category-link'; export default ComboboxView.extend({ @@ -41,7 +41,7 @@ export default ComboboxView.extend({ } }.property(), - template(item) { + comboTemplate(item) { let category; diff --git a/app/assets/javascripts/discourse/views/combo-box.js.es6 b/app/assets/javascripts/discourse/components/combo-box.js.es6 similarity index 92% rename from app/assets/javascripts/discourse/views/combo-box.js.es6 rename to app/assets/javascripts/discourse/components/combo-box.js.es6 index 96afbc9b89..e440f839ac 100644 --- a/app/assets/javascripts/discourse/views/combo-box.js.es6 +++ b/app/assets/javascripts/discourse/components/combo-box.js.es6 @@ -1,5 +1,4 @@ -// This view handles rendering of a combobox -export default Discourse.View.extend({ +export default Ember.Component.extend({ tagName: 'select', attributeBindings: ['tabindex'], classNames: ['combobox'], @@ -65,7 +64,7 @@ export default Discourse.View.extend({ o.selected = !!$(o).attr('selected'); }); - $elem.select2({formatResult: this.template, minimumResultsForSearch: 5, width: 'resolve'}); + $elem.select2({formatResult: this.comboTemplate, minimumResultsForSearch: 5, width: 'resolve'}); const castInteger = this.get('castInteger'); $elem.on("change", function (e) { diff --git a/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6 b/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6 index 19103360dd..807990d707 100644 --- a/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6 +++ b/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6 @@ -9,7 +9,7 @@ export default Ember.Component.extend({ if (this.get('condition')) { buffer.push('
'); } else { - return this._super(); + return this._super(buffer); } }, diff --git a/app/assets/javascripts/discourse/components/count-i18n.js.es6 b/app/assets/javascripts/discourse/components/count-i18n.js.es6 new file mode 100644 index 0000000000..28c908be23 --- /dev/null +++ b/app/assets/javascripts/discourse/components/count-i18n.js.es6 @@ -0,0 +1,8 @@ +export default Ember.Component.extend(Discourse.StringBuffer, { + tagName: 'span', + rerenderTriggers: ['count', 'suffix'], + + renderString: function(buffer) { + buffer.push(I18n.t(this.get('key') + (this.get('suffix') || ''), { count: this.get('count') })); + } +}); diff --git a/app/assets/javascripts/discourse/components/d-button.js.es6 b/app/assets/javascripts/discourse/components/d-button.js.es6 index 973405128f..7673e60ac4 100644 --- a/app/assets/javascripts/discourse/components/d-button.js.es6 +++ b/app/assets/javascripts/discourse/components/d-button.js.es6 @@ -26,7 +26,7 @@ export default Ember.Component.extend({ if (label) { buffer.push(label); } } else { // If no label or icon is present, yield - return this._super(); + return this._super(buffer); } }, diff --git a/app/assets/javascripts/discourse/components/input-tip.js.es6 b/app/assets/javascripts/discourse/components/input-tip.js.es6 new file mode 100644 index 0000000000..2ba1c074c4 --- /dev/null +++ b/app/assets/javascripts/discourse/components/input-tip.js.es6 @@ -0,0 +1,17 @@ +import StringBuffer from 'discourse/mixins/string-buffer'; +import { iconHTML } from 'discourse/helpers/fa-icon'; + +export default Ember.Component.extend(StringBuffer, { + classNameBindings: [':tip', 'good', 'bad'], + rerenderTriggers: ['validation'], + + bad: Em.computed.alias('validation.failed'), + good: Em.computed.not('bad'), + + renderString(buffer) { + const reason = this.get('validation.reason'); + if (reason) { + buffer.push(iconHTML(this.get('good') ? 'check' : 'times') + ' ' + reason); + } + } +}); diff --git a/app/assets/javascripts/discourse/views/popup_input_tip_view.js b/app/assets/javascripts/discourse/components/popup-input-tip.js.es6 similarity index 63% rename from app/assets/javascripts/discourse/views/popup_input_tip_view.js rename to app/assets/javascripts/discourse/components/popup-input-tip.js.es6 index a21d186295..db5b690802 100644 --- a/app/assets/javascripts/discourse/views/popup_input_tip_view.js +++ b/app/assets/javascripts/discourse/components/popup-input-tip.js.es6 @@ -1,23 +1,12 @@ -/** - This view extends the functionality of InputTipView with these extra features: - * it can be dismissed - * it bounces when it's shown - * it's absolutely positioned beside the input element, with the help of - extra css you'll need to write to line it up correctly. +import { iconHTML } from 'discourse/helpers/fa-icon'; - @class PopupInputTipView - @extends Discourse.View - @namespace Discourse - @module Discourse -**/ -Discourse.PopupInputTipView = Discourse.View.extend({ - templateName: 'popup_input_tip', +export default Ember.Component.extend({ classNameBindings: [':popup-tip', 'good', 'bad', 'shownAt::hide'], animateAttribute: null, bouncePixels: 6, bounceDelay: 100, - click: function() { + click() { this.set('shownAt', false); }, @@ -43,17 +32,23 @@ Discourse.PopupInputTipView = Discourse.View.extend({ } }.observes('shownAt'), - bounceLeft: function($elem) { + render(buffer) { + const reason = this.get('validation.reason'); + if (!reason) { return; } + + buffer.push("" + iconHTML('times-circle') + ""); + buffer.push(reason); + }, + + bounceLeft($elem) { for( var i = 0; i < 5; i++ ) { $elem.animate({ left: '+=' + this.bouncePixels }, this.bounceDelay).animate({ left: '-=' + this.bouncePixels }, this.bounceDelay); } }, - bounceRight: function($elem) { + bounceRight($elem) { for( var i = 0; i < 5; i++ ) { $elem.animate({ right: '-=' + this.bouncePixels }, this.bounceDelay).animate({ right: '+=' + this.bouncePixels }, this.bounceDelay); } } }); - -Discourse.View.registerHelper('popupInputTip', Discourse.PopupInputTipView); diff --git a/app/assets/javascripts/discourse/helpers/count-i18n.js.es6 b/app/assets/javascripts/discourse/helpers/count-i18n.js.es6 deleted file mode 100644 index 85fb9bc46d..0000000000 --- a/app/assets/javascripts/discourse/helpers/count-i18n.js.es6 +++ /dev/null @@ -1,17 +0,0 @@ -/** - Set up an i18n binding that will update as a count changes, complete with pluralization. - - @method countI18n - @for Handlebars -**/ -Ember.Handlebars.registerHelper('countI18n', function(key, options) { - var view = Discourse.View.extend(Discourse.StringBuffer, { - tagName: 'span', - rerenderTriggers: ['count', 'suffix'], - - renderString: function(buffer) { - buffer.push(I18n.t(key + (this.get('suffix') || ''), { count: this.get('count') })); - } - }); - return Ember.Handlebars.helpers.view.call(this, view, options); -}); diff --git a/app/assets/javascripts/discourse/helpers/custom-html.js.es6 b/app/assets/javascripts/discourse/helpers/custom-html.js.es6 index 42155096de..e802e058bd 100644 --- a/app/assets/javascripts/discourse/helpers/custom-html.js.es6 +++ b/app/assets/javascripts/discourse/helpers/custom-html.js.es6 @@ -1,4 +1,4 @@ -Handlebars.registerHelper('custom-html', function(name, contextString, options) { +Ember.Handlebars.registerHelper('custom-html', function(name, contextString, options) { var html = Discourse.HTML.getCustomHTML(name); if (html) { return html; } diff --git a/app/assets/javascripts/discourse/helpers/loading-spinner.es6 b/app/assets/javascripts/discourse/helpers/loading-spinner.es6 index 4d0cdb7af2..86ffcc89f1 100644 --- a/app/assets/javascripts/discourse/helpers/loading-spinner.es6 +++ b/app/assets/javascripts/discourse/helpers/loading-spinner.es6 @@ -1,5 +1,3 @@ -import ConditionalLoadingSpinner from 'discourse/components/conditional-loading-spinner'; - function renderSpinner(cssClass) { var html = "
- {{loading-spinner condition=canLoadMore}} + {{conditional-loading-spinner condition=canLoadMore}} {{/if}}
diff --git a/app/assets/javascripts/discourse/templates/components/basic-topic-list.hbs b/app/assets/javascripts/discourse/templates/components/basic-topic-list.hbs index 9fa600c9b9..f8afeb5755 100644 --- a/app/assets/javascripts/discourse/templates/components/basic-topic-list.hbs +++ b/app/assets/javascripts/discourse/templates/components/basic-topic-list.hbs @@ -1,4 +1,4 @@ -{{#loading-spinner condition=loading}} +{{#conditional-loading-spinner condition=loading}} {{#if topics}} {{topic-list showParticipants=showParticipants @@ -9,4 +9,4 @@ {{i18n 'choose_topic.none_found'}} {{/if}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/discourse/templates/components/category-drop.hbs b/app/assets/javascripts/discourse/templates/components/category-drop.hbs index 9e50cf11c5..803fe6f19c 100644 --- a/app/assets/javascripts/discourse/templates/components/category-drop.hbs +++ b/app/assets/javascripts/discourse/templates/components/category-drop.hbs @@ -16,7 +16,7 @@ {{#if categories}} -
+
{{#if subCategory}} diff --git a/app/assets/javascripts/discourse/templates/components/ip-lookup.hbs b/app/assets/javascripts/discourse/templates/components/ip-lookup.hbs index 578263c612..f58685e5c1 100644 --- a/app/assets/javascripts/discourse/templates/components/ip-lookup.hbs +++ b/app/assets/javascripts/discourse/templates/components/ip-lookup.hbs @@ -46,7 +46,7 @@ {{/if}} - {{#loading-spinner size="small" condition=otherAccountsLoading}} + {{#conditional-loading-spinner size="small" condition=otherAccountsLoading}} {{#if other_accounts.length}}
@@ -73,7 +73,7 @@
{{/if}} - {{/loading-spinner}} + {{/conditional-loading-spinner}}
{{/if}} diff --git a/app/assets/javascripts/discourse/templates/composer.hbs b/app/assets/javascripts/discourse/templates/composer.hbs index 454ff27932..20443650bc 100644 --- a/app/assets/javascripts/discourse/templates/composer.hbs +++ b/app/assets/javascripts/discourse/templates/composer.hbs @@ -57,13 +57,13 @@ so I'm going to stop rendering it until we figure out what's up
{{text-field value=model.title tabindex="2" id="reply-title" maxLength=maxTitleLength placeholderKey="composer.title_placeholder"}} - {{popupInputTip validation=view.titleValidation shownAt=view.showTitleTip}} + {{popup-input-tip validation=view.titleValidation shownAt=view.showTitleTip}}
{{#unless model.privateMessage}}
{{category-chooser valueAttribute="id" value=model.categoryId scopedCategoryId=scopedCategoryId tabindex="3"}} - {{popupInputTip validation=view.categoryValidation shownAt=view.showCategoryTip}} + {{popup-input-tip validation=view.categoryValidation shownAt=view.showCategoryTip}}
{{#if model.archetype.hasOptions}} @@ -80,7 +80,7 @@ so I'm going to stop rendering it until we figure out what's up
{{composer-text-area tabindex="4" value=model.reply}} - {{popupInputTip validation=view.replyValidation shownAt=view.showReplyTip}} + {{popup-input-tip validation=view.replyValidation shownAt=view.showReplyTip}}
diff --git a/app/assets/javascripts/discourse/templates/discovery.hbs b/app/assets/javascripts/discourse/templates/discovery.hbs index 1bf0814aaa..be18d07bae 100644 --- a/app/assets/javascripts/discourse/templates/discovery.hbs +++ b/app/assets/javascripts/discourse/templates/discovery.hbs @@ -10,7 +10,7 @@
-{{loading-spinner condition=loading}} +{{conditional-loading-spinner condition=loading}}
diff --git a/app/assets/javascripts/discourse/templates/discovery/topics.hbs b/app/assets/javascripts/discourse/templates/discovery/topics.hbs index 494da1abba..bdcc9800fb 100644 --- a/app/assets/javascripts/discourse/templates/discovery/topics.hbs +++ b/app/assets/javascripts/discourse/templates/discovery/topics.hbs @@ -25,7 +25,7 @@ {{#if topicTrackingState.hasIncoming}}
- {{countI18n topic_count_ suffix=topicTrackingState.filter count=topicTrackingState.incomingCount}} + {{count-i18n key=topic_count_ suffix=topicTrackingState.filter count=topicTrackingState.incomingCount}} {{i18n 'click_to_show'}}
@@ -51,7 +51,7 @@
- {{loading-spinner condition=loadingMore}} + {{conditional-loading-spinner condition=loadingMore}} {{#if allLoaded}} {{#if showDismissRead}} diff --git a/app/assets/javascripts/discourse/templates/exception.hbs b/app/assets/javascripts/discourse/templates/exception.hbs index e52073f2f2..9416f2b436 100644 --- a/app/assets/javascripts/discourse/templates/exception.hbs +++ b/app/assets/javascripts/discourse/templates/exception.hbs @@ -16,7 +16,7 @@ {{#each buttonData in enabledButtons}} {{/each}} - {{loading-spinner condition=loading}} + {{conditional-loading-spinner condition=loading}}
diff --git a/app/assets/javascripts/discourse/templates/mobile/components/basic-topic-list.hbs b/app/assets/javascripts/discourse/templates/mobile/components/basic-topic-list.hbs index 9d07aba9cf..2dfeb9ad4a 100644 --- a/app/assets/javascripts/discourse/templates/mobile/components/basic-topic-list.hbs +++ b/app/assets/javascripts/discourse/templates/mobile/components/basic-topic-list.hbs @@ -1,4 +1,4 @@ -{{#loading-spinner condition=loading}} +{{#conditional-loading-spinner condition=loading}} {{#if topics}} @@ -54,4 +54,4 @@ {{i18n 'choose_topic.none_found'}} {{/if}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/discourse/templates/mobile/discovery/topics.hbs b/app/assets/javascripts/discourse/templates/mobile/discovery/topics.hbs index feb13c5d46..bbedfb7ca8 100644 --- a/app/assets/javascripts/discourse/templates/mobile/discovery/topics.hbs +++ b/app/assets/javascripts/discourse/templates/mobile/discovery/topics.hbs @@ -7,7 +7,7 @@ {{#if topicTrackingState.hasIncoming}}
- {{countI18n topic_count_ suffix=topicTrackingState.filter count=topicTrackingState.incomingCount}} + {{count-i18n key=topic_count_ suffix=topicTrackingState.filter count=topicTrackingState.incomingCount}} {{i18n 'click_to_show'}}
{{/if}} @@ -22,7 +22,7 @@
- {{loading-spinner condition=loadingMore}} + {{conditional-loading-spinner condition=loadingMore}} {{#if allLoaded}} {{#if showDismissRead}} diff --git a/app/assets/javascripts/discourse/templates/modal/bulk_change_category.hbs b/app/assets/javascripts/discourse/templates/modal/bulk_change_category.hbs index 6239773fd9..cc96a49d6f 100644 --- a/app/assets/javascripts/discourse/templates/modal/bulk_change_category.hbs +++ b/app/assets/javascripts/discourse/templates/modal/bulk_change_category.hbs @@ -2,6 +2,6 @@

{{category-chooser value=newCategoryId}}

-{{#loading-spinner condition=loading}} +{{#conditional-loading-spinner condition=loading}} {{d-button action="changeCategory" label="topics.bulk.change_category"}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/discourse/templates/modal/create-account.hbs b/app/assets/javascripts/discourse/templates/modal/create-account.hbs index 87e472078d..acac3c98d5 100644 --- a/app/assets/javascripts/discourse/templates/modal/create-account.hbs +++ b/app/assets/javascripts/discourse/templates/modal/create-account.hbs @@ -88,11 +88,11 @@ {{#if showCreateForm}} {{/if}} {{/unless}} diff --git a/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs b/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs index d2b28eb26d..86c25e7898 100644 --- a/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs +++ b/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs @@ -9,16 +9,16 @@ {{#if pinned_globally}}

{{i18n "topic.feature_topic.global_pin_note"}}

- {{#loading-spinner size="small" condition=loading}} + {{#conditional-loading-spinner size="small" condition=loading}} {{{i18n "topic.feature_topic.already_pinned_globally" count=pinnedGloballyCount}}} - {{/loading-spinner}} + {{/conditional-loading-spinner}}

{{else}}

{{i18n "topic.feature_topic.pin_note"}}

- {{#loading-spinner size="small" condition=loading}} + {{#conditional-loading-spinner size="small" condition=loading}} {{{alreadyPinnedMessage}}} - {{/loading-spinner}} + {{/conditional-loading-spinner}}

{{/if}} @@ -32,9 +32,9 @@

{{{pinMessage}}}

{{i18n "topic.feature_topic.pin_note"}}

- {{#loading-spinner size="small" condition=loading}} + {{#conditional-loading-spinner size="small" condition=loading}} {{{alreadyPinnedMessage}}} - {{/loading-spinner}} + {{/conditional-loading-spinner}}

@@ -47,9 +47,9 @@

{{i18n "topic.feature_topic.pin_globally"}}

{{i18n "topic.feature_topic.global_pin_note"}}

- {{#loading-spinner size="small" condition=loading}} + {{#conditional-loading-spinner size="small" condition=loading}} {{{i18n "topic.feature_topic.already_pinned_globally" count=pinnedGloballyCount}}} - {{/loading-spinner}} + {{/conditional-loading-spinner}}

@@ -71,9 +71,9 @@ {{/if}}

{{i18n "topic.feature_topic.banner_note"}}

- {{#loading-spinner size="small" condition=loading}} + {{#conditional-loading-spinner size="small" condition=loading}} {{{i18n "topic.feature_topic.already_banner" count=bannerCount}}} - {{/loading-spinner}} + {{/conditional-loading-spinner}}

diff --git a/app/assets/javascripts/discourse/templates/modal/history.hbs b/app/assets/javascripts/discourse/templates/modal/history.hbs index 6a1bd9e86d..48ef43d59c 100644 --- a/app/assets/javascripts/discourse/templates/modal/history.hbs +++ b/app/assets/javascripts/discourse/templates/modal/history.hbs @@ -4,9 +4,9 @@
- {{#loading-spinner condition=loading size="small"}} + {{#conditional-loading-spinner condition=loading size="small"}} {{boundI18n revisionsTextKey previousBinding="previousVersion" currentBinding="current_version" totalBinding="version_count"}} - {{/loading-spinner}} + {{/conditional-loading-spinner}}
diff --git a/app/assets/javascripts/discourse/templates/modal/login.hbs b/app/assets/javascripts/discourse/templates/modal/login.hbs index 3034d390d9..4e528dc910 100644 --- a/app/assets/javascripts/discourse/templates/modal/login.hbs +++ b/app/assets/javascripts/discourse/templates/modal/login.hbs @@ -56,5 +56,5 @@   {{i18n 'login.authenticating'}} {{/if}} - {{loading-spinner condition=showSpinner size="small"}} + {{conditional-loading-spinner condition=showSpinner size="small"}} diff --git a/app/assets/javascripts/discourse/templates/modal/post-enqueued.hbs b/app/assets/javascripts/discourse/templates/modal/post-enqueued.hbs index 1ebdd0c4c4..95065ab9ca 100644 --- a/app/assets/javascripts/discourse/templates/modal/post-enqueued.hbs +++ b/app/assets/javascripts/discourse/templates/modal/post-enqueued.hbs @@ -1,7 +1,7 @@
- {{#loading-spinner condition=postStream.loadingFilter}} + {{#conditional-loading-spinner condition=postStream.loadingFilter}} {{#if loadedAllPosts}} {{view 'topic-closing' topic=model}} @@ -113,7 +113,7 @@ {{/if}} {{/if}} - {{/loading-spinner}} + {{/conditional-loading-spinner}} @@ -121,7 +121,7 @@ {{else}}
- {{#loading-spinner condition=noErrorYet}} + {{#conditional-loading-spinner condition=noErrorYet}} {{#if notFoundHtml}} {{{notFoundHtml}}} {{else}} @@ -135,9 +135,9 @@ {{d-button action="retryLoading" class="btn-primary topic-retry" icon="refresh" label="errors.buttons.again"}} {{/if}}
- {{loading-spinner condition=retrying}} + {{conditional-loading-spinner condition=retrying}} {{/if}} - {{/loading-spinner}} + {{/conditional-loading-spinner}} {{/if}} diff --git a/app/assets/javascripts/discourse/templates/user/invited.hbs b/app/assets/javascripts/discourse/templates/user/invited.hbs index 3d394fe312..c3314fe4b6 100644 --- a/app/assets/javascripts/discourse/templates/user/invited.hbs +++ b/app/assets/javascripts/discourse/templates/user/invited.hbs @@ -69,7 +69,7 @@ {{/each}}
- {{loading-spinner condition=invitesLoading}} + {{conditional-loading-spinner condition=invitesLoading}} {{else}} {{#if canBulkInvite}} diff --git a/app/assets/javascripts/discourse/templates/user/notifications.hbs b/app/assets/javascripts/discourse/templates/user/notifications.hbs index ab18934d4e..e3a1373905 100644 --- a/app/assets/javascripts/discourse/templates/user/notifications.hbs +++ b/app/assets/javascripts/discourse/templates/user/notifications.hbs @@ -23,7 +23,7 @@ {{/each}} -{{#loading-spinner condition=loading}} +{{#conditional-loading-spinner condition=loading}} {{#unless canLoadMore}} {{#if showDismissButton}}
@@ -31,4 +31,4 @@
{{/if}} {{/unless}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/discourse/templates/users.hbs b/app/assets/javascripts/discourse/templates/users.hbs index 58a20209e0..45ea960e7c 100644 --- a/app/assets/javascripts/discourse/templates/users.hbs +++ b/app/assets/javascripts/discourse/templates/users.hbs @@ -6,7 +6,7 @@ {{text-field value=nameInput placeholderKey="directory.filter_name" class="filter-name"}} - {{#loading-spinner condition=model.loading}} + {{#conditional-loading-spinner condition=model.loading}} {{#if model.length}}
{{i18n "directory.total_rows" count=model.totalRows}}
@@ -43,12 +43,12 @@ - {{loading-spinner condition=model.loadingMore}} + {{conditional-loading-spinner condition=model.loadingMore}} {{else}}

{{i18n "directory.no_results"}}

{{/if}} - {{/loading-spinner}} + {{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/discourse/views/input-tip.js.es6 b/app/assets/javascripts/discourse/views/input-tip.js.es6 deleted file mode 100644 index 6caf2dad67..0000000000 --- a/app/assets/javascripts/discourse/views/input-tip.js.es6 +++ /dev/null @@ -1,17 +0,0 @@ -import StringBuffer from 'discourse/mixins/string-buffer'; - -export default Discourse.View.extend(StringBuffer, { - classNameBindings: [':tip', 'good', 'bad'], - rerenderTriggers: ['validation'], - - bad: Em.computed.alias('validation.failed'), - good: Em.computed.not('bad'), - - renderString: function(buffer) { - var reason = this.get('validation.reason'); - if (reason) { - var icon = this.get('good') ? 'fa-check' : 'fa-times'; - return buffer.push(" " + reason); - } - } -}); diff --git a/app/assets/javascripts/discourse/views/view.js.es6 b/app/assets/javascripts/discourse/views/view.js.es6 index f939764ebb..03f49906f8 100644 --- a/app/assets/javascripts/discourse/views/view.js.es6 +++ b/app/assets/javascripts/discourse/views/view.js.es6 @@ -1,17 +1,3 @@ import Presence from 'discourse/mixins/presence'; -const View = Ember.View.extend(Presence, {}); - -View.reopenClass({ - registerHelper(helperName, helperClass) { - Ember.Handlebars.registerHelper(helperName, function(options) { - var hash = options.hash, - types = options.hashTypes; - - Discourse.Utilities.normalizeHash(hash, types); - return Ember.Handlebars.helpers.view.call(this, helperClass, options); - }); - } -}); - -export default View; +export default Ember.View.extend(Presence); diff --git a/app/assets/javascripts/ember_include.js.erb b/app/assets/javascripts/ember_include.js.erb index f124141c39..15cc71aec5 100644 --- a/app/assets/javascripts/ember_include.js.erb +++ b/app/assets/javascripts/ember_include.js.erb @@ -1,5 +1,6 @@ <% if Rails.env.development? || Rails.env.test? + require_asset ("ember-template-compiler.js") require_asset ("development/ember.js") else require_asset ("production/ember.js") diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js index 6d856ec381..48fce6d514 100644 --- a/app/assets/javascripts/main_include.js +++ b/app/assets/javascripts/main_include.js @@ -42,7 +42,7 @@ //= require ./discourse/views/container //= require ./discourse/views/modal-body //= require ./discourse/views/flag -//= require ./discourse/views/combo-box +//= require ./discourse/components/combo-box //= require ./discourse/views/button //= require ./discourse/components/dropdown-button //= require ./discourse/components/notifications-button diff --git a/test/javascripts/views/view-test.js.es6 b/test/javascripts/views/view-test.js.es6 deleted file mode 100644 index ee62c02de7..0000000000 --- a/test/javascripts/views/view-test.js.es6 +++ /dev/null @@ -1,34 +0,0 @@ -import Presence from 'discourse/mixins/presence'; - -var oldHelpers; - -module("Discourse.View", { - setup: function() { - oldHelpers = Ember.Handlebars.helpers; - }, - - teardown: function() { - Ember.Handlebars.helpers = oldHelpers; - } -}); - -test("mixes in Presence", function() { - ok(Presence.detect(Discourse.View.create())); -}); - -test("registerHelper: enables embedding a child view in a parent view via dedicated, named helper instead of generic 'view' helper", function() { - Discourse.View.registerHelper("childViewHelper", Ember.View.extend({ - template: Ember.Handlebars.compile('{{view.text}}') - })); - - var parentView = Ember.View.extend({ - template: Ember.Handlebars.compile('{{childViewHelper id="child" text="foo"}}') - }).create(); - - Ember.run(function() { - parentView.appendTo("#qunit-fixture"); - }); - - equal(parentView.$("#child").length, 1, "child view registered as helper is appended to the parent view"); - equal(parentView.$("#child").text(), "foo", "child view registered as helper gets parameters provided during helper invocation in parent's template"); -}); diff --git a/vendor/assets/javascripts/development/ember.js b/vendor/assets/javascripts/development/ember.js index 0b4deefa8d..5c1c432e1d 100644 --- a/vendor/assets/javascripts/development/ember.js +++ b/vendor/assets/javascripts/development/ember.js @@ -5,7 +5,7 @@ * Portions Copyright 2008-2011 Apple Inc. All rights reserved. * @license Licensed under MIT license * See https://raw.github.com/emberjs/ember.js/master/LICENSE - * @version 1.9.0 + * @version 1.10.1 */ (function() { @@ -32,7 +32,7 @@ var enifed, requireModule, eriuqer, requirejs, Ember; seen[name] = {}; if (!registry[name]) { - throw new Error("Could not find module " + name); + throw new Error('Could not find module ' + name); } var mod = registry[name]; @@ -56,9 +56,11 @@ var enifed, requireModule, eriuqer, requirejs, Ember; }; function resolve(child, name) { - if (child.charAt(0) !== '.') { return child; } - var parts = child.split("/"); - var parentBase = name.split("/").slice(0, -1); + if (child.charAt(0) !== '.') { + return child; + } + var parts = child.split('/'); + var parentBase = name.split('/').slice(0, -1); for (var i=0, l=parts.length; i 0) { + var firstParam = params[0]; + // Only bother with subscriptions if the first argument + // is a stream itself, and not a primitive. + if (isStream(firstParam)) { + var onDependentKeyNotify = function onDependentKeyNotify(stream) { + stream.value(); + lazyValue.notify(); + }; + for (i = 0; i < dependentKeys.length; i++) { + var childParam = firstParam.get(dependentKeys[i]); + childParam.value(); + childParam.subscribe(onDependentKeyNotify); + } + } + } + + return lazyValue; + } + } + + return new Helper(helperFunc); + } + }); +enifed("ember-htmlbars/compat/register-bound-helper", + ["ember-htmlbars/helpers","ember-htmlbars/compat/make-bound-helper","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-htmlbars + */ + + var helpers = __dependency1__["default"]; + var makeBoundHelper = __dependency2__["default"]; + + var slice = [].slice; /** - Register a bound helper or custom view helper. + Register a bound handlebars helper. Bound helpers behave similarly to regular + handlebars helpers, with the added ability to re-render when the underlying data + changes. - ## Simple bound helper example + ## Simple example ```javascript - Ember.Handlebars.helper('capitalize', function(value) { - return value.toUpperCase(); + Ember.Handlebars.registerBoundHelper('capitalize', function(value) { + return Ember.String.capitalize(value); }); ``` @@ -4797,403 +5244,1183 @@ enifed("ember-handlebars-compiler", In this case, when the `name` property of the template's context changes, the rendered value of the helper will update to reflect this change. - For more examples of bound helpers, see documentation for - `Ember.Handlebars.registerBoundHelper`. + ## Example with options - ## Custom view helper example - - Assuming a view subclass named `App.CalendarView` were defined, a helper - for rendering instances of this view could be registered as follows: + Like normal handlebars helpers, bound helpers have access to the options + passed into the helper call. ```javascript - Ember.Handlebars.helper('calendar', App.CalendarView): + Ember.Handlebars.registerBoundHelper('repeat', function(value, options) { + var count = options.hash.count; + var a = []; + while(a.length < count) { + a.push(value); + } + return a.join(''); + }); ``` - The above bound helper can be used inside of templates as follows: + This helper could be used in a template as follows: ```handlebars - {{calendar}} + {{repeat text count=3}} ``` - Which is functionally equivalent to: + ## Example with bound options + + Bound hash options are also supported. Example: ```handlebars - {{view 'calendar'}} + {{repeat text count=numRepeats}} ``` - Options in the helper will be passed to the view in exactly the same - manner as with the `view` helper. + In this example, count will be bound to the value of + the `numRepeats` property on the context. If that property + changes, the helper will be re-rendered. - @method helper + ## Example with extra dependencies + + The `Ember.Handlebars.registerBoundHelper` method takes a variable length + third parameter which indicates extra dependencies on the passed in value. + This allows the handlebars helper to update when these dependencies change. + + ```javascript + Ember.Handlebars.registerBoundHelper('capitalizeName', function(value) { + return value.get('name').toUpperCase(); + }, 'name'); + ``` + + ## Example with multiple bound properties + + `Ember.Handlebars.registerBoundHelper` supports binding to + multiple properties, e.g.: + + ```javascript + Ember.Handlebars.registerBoundHelper('concatenate', function() { + var values = Array.prototype.slice.call(arguments, 0, -1); + return values.join('||'); + }); + ``` + + Which allows for template syntax such as `{{concatenate prop1 prop2}}` or + `{{concatenate prop1 prop2 prop3}}`. If any of the properties change, + the helper will re-render. Note that dependency keys cannot be + using in conjunction with multi-property helpers, since it is ambiguous + which property the dependent keys would belong to. + + ## Use with unbound helper + + The `{{unbound}}` helper can be used with bound helper invocations + to render them in their unbound form, e.g. + + ```handlebars + {{unbound capitalize name}} + ``` + + In this example, if the name property changes, the helper + will not re-render. + + ## Use with blocks not supported + + Bound helpers do not support use with Handlebars blocks or + the addition of child views of any kind. + + @method registerBoundHelper @for Ember.Handlebars @param {String} name - @param {Function|Ember.View} function or view class constructor + @param {Function} function @param {String} dependentKeys* */ - EmberHandlebars.helper = function(name, value) { - if (!View) { View = requireModule('ember-views/views/view')['default']; } // ES6TODO: stupid circular dep - if (!Component) { Component = requireModule('ember-views/views/component')['default']; } // ES6TODO: stupid circular dep + __exports__["default"] = function registerBoundHelper(name, fn) { + var boundHelperArgs = slice.call(arguments, 1); + var boundFn = makeBoundHelper.apply(this, boundHelperArgs); - Ember.assert("You tried to register a component named '" + name + - "', but component names must include a '-'", !Component.detect(value) || name.match(/-/)); - - if (View.detect(value)) { - EmberHandlebars.registerHelper(name, EmberHandlebars.makeViewHelper(value)); - } else { - EmberHandlebars.registerBoundHelper.apply(null, arguments); - } - }; - - /** - Returns a helper function that renders the provided ViewClass. - - Used internally by Ember.Handlebars.helper and other methods - involving helper/component registration. - - @private - @method makeViewHelper - @for Ember.Handlebars - @param {Function} ViewClass view class constructor - @since 1.2.0 - */ - EmberHandlebars.makeViewHelper = function(ViewClass) { - return function(options) { - Ember.assert("You can only pass attributes (such as name=value) not bare " + - "values to a helper for a View found in '" + ViewClass.toString() + "'", arguments.length < 2); - return EmberHandlebars.helpers.view.call(this, ViewClass, options); - }; - }; - - /** - @class helpers - @namespace Ember.Handlebars - */ - EmberHandlebars.helpers = objectCreate(Handlebars.helpers); - - /** - Override the the opcode compiler and JavaScript compiler for Handlebars. - - @class Compiler - @namespace Ember.Handlebars - @private - @constructor - */ - EmberHandlebars.Compiler = function() {}; - - // Handlebars.Compiler doesn't exist in runtime-only - if (Handlebars.Compiler) { - EmberHandlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype); + helpers[name] = boundFn; } - - EmberHandlebars.Compiler.prototype.compiler = EmberHandlebars.Compiler; - - /** - @class JavaScriptCompiler - @namespace Ember.Handlebars - @private - @constructor - */ - EmberHandlebars.JavaScriptCompiler = function() {}; - - // Handlebars.JavaScriptCompiler doesn't exist in runtime-only - if (Handlebars.JavaScriptCompiler) { - EmberHandlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype); - EmberHandlebars.JavaScriptCompiler.prototype.compiler = EmberHandlebars.JavaScriptCompiler; - } - - - EmberHandlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars"; - - EmberHandlebars.JavaScriptCompiler.prototype.initializeBuffer = function() { - return "''"; - }; - - /** - Override the default buffer for Ember Handlebars. By default, Handlebars - creates an empty String at the beginning of each invocation and appends to - it. Ember's Handlebars overrides this to append to a single shared buffer. - - @private - @method appendToBuffer - @param string {String} - */ - EmberHandlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) { - return "data.buffer.push("+string+");"; - }; - - /** - Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that - all simple mustaches in Ember's Handlebars will also set up an observer to - keep the DOM up to date when the underlying property changes. - - @private - @method mustache - @for Ember.Handlebars.Compiler - @param mustache - */ - EmberHandlebars.Compiler.prototype.mustache = function(mustache) { - if (!(mustache.params.length || mustache.hash)) { - var id = new Handlebars.AST.IdNode([{ part: '_triageMustache' }]); - - // Update the mustache node to include a hash value indicating whether the original node - // was escaped. This will allow us to properly escape values when the underlying value - // changes and we need to re-render the value. - if (!mustache.escaped) { - mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]); - mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]); - } - mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped); - } - - return Handlebars.Compiler.prototype.mustache.call(this, mustache); - }; - - /** - Used for precompilation of Ember Handlebars templates. This will not be used - during normal app execution. - - @method precompile - @for Ember.Handlebars - @static - @param {String|Object} value The template to precompile or an Handlebars AST - @param {Boolean} asObject optional parameter, defaulting to true, of whether or not the - compiled template should be returned as an Object or a String - */ - EmberHandlebars.precompile = function(value, asObject) { - var ast = Handlebars.parse(value); - - var options = { - knownHelpers: { - action: true, - unbound: true, - 'bind-attr': true, - template: true, - view: true, - _triageMustache: true - }, - data: true, - stringParams: true - }; - - asObject = asObject === undefined ? true : asObject; - - var environment = new EmberHandlebars.Compiler().compile(ast, options); - return new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, asObject); - }; - - // We don't support this for Handlebars runtime-only - if (Handlebars.compile) { - /** - The entry point for Ember Handlebars. This replaces the default - `Handlebars.compile` and turns on template-local data and String - parameters. - - @method compile - @for Ember.Handlebars - @static - @param {String} string The template to compile - @return {Function} - */ - EmberHandlebars.compile = function(string) { - var ast = Handlebars.parse(string); - var options = { data: true, stringParams: true }; - var environment = new EmberHandlebars.Compiler().compile(ast, options); - var templateSpec = new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, true); - - var template = EmberHandlebars.template(templateSpec); - template.isMethod = false; //Make sure we don't wrap templates with ._super - - return template; - }; - } - - __exports__["default"] = EmberHandlebars; }); -enifed("ember-handlebars", - ["ember-handlebars-compiler","ember-metal/core","ember-runtime/system/lazy_load","ember-handlebars/loader","ember-handlebars/ext","ember-handlebars/string","ember-handlebars/helpers/binding","ember-handlebars/helpers/if_unless","ember-handlebars/helpers/with","ember-handlebars/helpers/bind_attr","ember-handlebars/helpers/collection","ember-handlebars/helpers/view","ember-handlebars/helpers/unbound","ember-handlebars/helpers/debug","ember-handlebars/helpers/each","ember-handlebars/helpers/template","ember-handlebars/helpers/partial","ember-handlebars/helpers/yield","ember-handlebars/helpers/loc","ember-handlebars/controls/checkbox","ember-handlebars/controls/select","ember-handlebars/controls/text_area","ember-handlebars/controls/text_field","ember-handlebars/controls/text_support","ember-handlebars/controls","ember-handlebars/component_lookup","ember-handlebars/views/handlebars_bound_view","ember-handlebars/views/metamorph_view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __dependency27__, __dependency28__, __exports__) { +enifed("ember-htmlbars/helpers", + ["ember-metal/platform","ember-htmlbars/system/helper","exports"], + function(__dependency1__, __dependency2__, __exports__) { "use strict"; - var EmberHandlebars = __dependency1__["default"]; - var Ember = __dependency2__["default"]; - // to add to globals - - var runLoadHooks = __dependency3__.runLoadHooks; - var bootstrap = __dependency4__["default"]; - - var makeBoundHelper = __dependency5__.makeBoundHelper; - var registerBoundHelper = __dependency5__.registerBoundHelper; - var helperMissingHelper = __dependency5__.helperMissingHelper; - var blockHelperMissingHelper = __dependency5__.blockHelperMissingHelper; - var handlebarsGet = __dependency5__.handlebarsGet; - - - // side effect of extending StringUtils of htmlSafe - - var bind = __dependency7__.bind; - var _triageMustacheHelper = __dependency7__._triageMustacheHelper; - var resolveHelper = __dependency7__.resolveHelper; - var bindHelper = __dependency7__.bindHelper; - - var ifHelper = __dependency8__.ifHelper; - var boundIfHelper = __dependency8__.boundIfHelper; - var unboundIfHelper = __dependency8__.unboundIfHelper; - var unlessHelper = __dependency8__.unlessHelper; - - var withHelper = __dependency9__["default"]; - - var bindAttrHelper = __dependency10__.bindAttrHelper; - var bindAttrHelperDeprecated = __dependency10__.bindAttrHelperDeprecated; - var bindClasses = __dependency10__.bindClasses; - - var collectionHelper = __dependency11__["default"]; - var ViewHelper = __dependency12__.ViewHelper; - var viewHelper = __dependency12__.viewHelper; - var unboundHelper = __dependency13__["default"]; - var logHelper = __dependency14__.logHelper; - var debuggerHelper = __dependency14__.debuggerHelper; - var EachView = __dependency15__.EachView; - var eachHelper = __dependency15__.eachHelper; - var templateHelper = __dependency16__["default"]; - var partialHelper = __dependency17__["default"]; - var yieldHelper = __dependency18__["default"]; - var locHelper = __dependency19__["default"]; - - - var Checkbox = __dependency20__["default"]; - var Select = __dependency21__.Select; - var SelectOption = __dependency21__.SelectOption; - var SelectOptgroup = __dependency21__.SelectOptgroup; - var TextArea = __dependency22__["default"]; - var TextField = __dependency23__["default"]; - var TextSupport = __dependency24__["default"]; - var inputHelper = __dependency25__.inputHelper; - var textareaHelper = __dependency25__.textareaHelper; - - var ComponentLookup = __dependency26__["default"]; - var _HandlebarsBoundView = __dependency27__._HandlebarsBoundView; - var SimpleHandlebarsView = __dependency27__.SimpleHandlebarsView; - var _MetamorphView = __dependency28__["default"]; - var _SimpleMetamorphView = __dependency28__._SimpleMetamorphView; - var _Metamorph = __dependency28__._Metamorph; - - /** - Ember Handlebars - @module ember - @submodule ember-handlebars - @requires ember-views + @submodule ember-htmlbars */ - // Ember.Handlebars.Globals - EmberHandlebars.bootstrap = bootstrap; - EmberHandlebars.makeBoundHelper = makeBoundHelper; - EmberHandlebars.registerBoundHelper = registerBoundHelper; - EmberHandlebars.resolveHelper = resolveHelper; - EmberHandlebars.bind = bind; - EmberHandlebars.bindClasses = bindClasses; - EmberHandlebars.EachView = EachView; - EmberHandlebars.ViewHelper = ViewHelper; + var o_create = __dependency1__.create; + /** + @private + @property helpers + */ + var helpers = o_create(null); - // Ember Globals - Ember.Handlebars = EmberHandlebars; - EmberHandlebars.get = handlebarsGet; - Ember.ComponentLookup = ComponentLookup; - Ember._SimpleHandlebarsView = SimpleHandlebarsView; - Ember._HandlebarsBoundView = _HandlebarsBoundView; - Ember._SimpleMetamorphView = _SimpleMetamorphView; - Ember._MetamorphView = _MetamorphView; - Ember._Metamorph = _Metamorph; - Ember.TextSupport = TextSupport; - Ember.Checkbox = Checkbox; - Ember.Select = Select; - Ember.SelectOption = SelectOption; - Ember.SelectOptgroup = SelectOptgroup; - Ember.TextArea = TextArea; - Ember.TextField = TextField; - Ember.TextSupport = TextSupport; + /** + @module ember + @submodule ember-htmlbars + */ - // register helpers - EmberHandlebars.registerHelper('helperMissing', helperMissingHelper); - EmberHandlebars.registerHelper('blockHelperMissing', blockHelperMissingHelper); - EmberHandlebars.registerHelper('bind', bindHelper); - EmberHandlebars.registerHelper('boundIf', boundIfHelper); - EmberHandlebars.registerHelper('_triageMustache', _triageMustacheHelper); - EmberHandlebars.registerHelper('unboundIf', unboundIfHelper); - EmberHandlebars.registerHelper('with', withHelper); - EmberHandlebars.registerHelper('if', ifHelper); - EmberHandlebars.registerHelper('unless', unlessHelper); - EmberHandlebars.registerHelper('bind-attr', bindAttrHelper); - EmberHandlebars.registerHelper('bindAttr', bindAttrHelperDeprecated); - EmberHandlebars.registerHelper('collection', collectionHelper); - EmberHandlebars.registerHelper("log", logHelper); - EmberHandlebars.registerHelper("debugger", debuggerHelper); - EmberHandlebars.registerHelper("each", eachHelper); - EmberHandlebars.registerHelper("loc", locHelper); - EmberHandlebars.registerHelper("partial", partialHelper); - EmberHandlebars.registerHelper("template", templateHelper); - EmberHandlebars.registerHelper("yield", yieldHelper); - EmberHandlebars.registerHelper("view", viewHelper); - EmberHandlebars.registerHelper("unbound", unboundHelper); - EmberHandlebars.registerHelper("input", inputHelper); - EmberHandlebars.registerHelper("textarea", textareaHelper); + var Helper = __dependency2__["default"]; - // run load hooks - runLoadHooks('Ember.Handlebars', EmberHandlebars); + /** + @private + @method _registerHelper + @for Ember.HTMLBars + @param {String} name + @param {Object|Function} helperFunc the helper function to add + */ + function registerHelper(name, helperFunc) { + var helper; - __exports__["default"] = EmberHandlebars; + if (helperFunc && helperFunc.isHelper) { + helper = helperFunc; + } else { + helper = new Helper(helperFunc); + } + + helpers[name] = helper; + } + + __exports__.registerHelper = registerHelper;__exports__["default"] = helpers; }); -enifed("ember-handlebars/component_lookup", - ["ember-runtime/system/object","exports"], +enifed("ember-htmlbars/helpers/bind-attr", + ["ember-metal/core","ember-runtime/system/string","ember-views/attr_nodes/attr_node","ember-views/attr_nodes/legacy_bind","ember-metal/keys","ember-htmlbars/helpers","ember-metal/enumerable_utils","ember-metal/streams/utils","ember-views/streams/class_name_binding","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-htmlbars + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + + var fmt = __dependency2__.fmt; + var AttrNode = __dependency3__["default"]; + var LegacyBindAttrNode = __dependency4__["default"]; + var keys = __dependency5__["default"]; + var helpers = __dependency6__["default"]; + var map = __dependency7__.map; + var isStream = __dependency8__.isStream; + var concat = __dependency8__.concat; + var streamifyClassNameBinding = __dependency9__.streamifyClassNameBinding; + + /** + `bind-attr` allows you to create a binding between DOM element attributes and + Ember objects. For example: + + ```handlebars + imageTitle}} + ``` + + The above handlebars template will fill the ``'s `src` attribute with + the value of the property referenced with `imageUrl` and its `alt` + attribute with the value of the property referenced with `imageTitle`. + + If the rendering context of this template is the following object: + + ```javascript + { + imageUrl: 'http://lolcats.info/haz-a-funny', + imageTitle: 'A humorous image of a cat' + } + ``` + + The resulting HTML output will be: + + ```html + A humorous image of a cat + ``` + + `bind-attr` cannot redeclare existing DOM element attributes. The use of `src` + in the following `bind-attr` example will be ignored and the hard coded value + of `src="/failwhale.gif"` will take precedence: + + ```handlebars + imageTitle}} + ``` + + ### `bind-attr` and the `class` attribute + + `bind-attr` supports a special syntax for handling a number of cases unique + to the `class` DOM element attribute. The `class` attribute combines + multiple discrete values into a single attribute as a space-delimited + list of strings. Each string can be: + + * a string return value of an object's property. + * a boolean return value of an object's property + * a hard-coded value + + A string return value works identically to other uses of `bind-attr`. The + return value of the property will become the value of the attribute. For + example, the following view and template: + + ```javascript + AView = View.extend({ + someProperty: function() { + return "aValue"; + }.property() + }) + ``` + + ```handlebars + + ``` + + Result in the following rendered output: + + ```html + + ``` + + A boolean return value will insert a specified class name if the property + returns `true` and remove the class name if the property returns `false`. + + A class name is provided via the syntax + `somePropertyName:class-name-if-true`. + + ```javascript + AView = View.extend({ + someBool: true + }) + ``` + + ```handlebars + + ``` + + Result in the following rendered output: + + ```html + + ``` + + An additional section of the binding can be provided if you want to + replace the existing class instead of removing it when the boolean + value changes: + + ```handlebars + + ``` + + A hard-coded value can be used by prepending `:` to the desired + class name: `:class-name-to-always-apply`. + + ```handlebars + + ``` + + Results in the following rendered output: + + ```html + + ``` + + All three strategies - string return value, boolean return value, and + hard-coded value – can be combined in a single declaration: + + ```handlebars + + ``` + + @method bind-attr + @for Ember.Handlebars.helpers + @param {Hash} options + @return {String} HTML string + */ + function bindAttrHelper(params, hash, options, env) { + var element = options.element; + + Ember.assert("You must specify at least one hash argument to bind-attr", !!keys(hash).length); + + var view = this; + + // Handle classes differently, as we can bind multiple classes + var classNameBindings = hash['class']; + if (classNameBindings !== null && classNameBindings !== undefined) { + if (!isStream(classNameBindings)) { + classNameBindings = applyClassNameBindings(classNameBindings, view); + } + + var classView = new AttrNode('class', classNameBindings); + classView._morph = env.dom.createAttrMorph(element, 'class'); + + Ember.assert( + 'You cannot set `class` manually and via `{{bind-attr}}` helper on the same element. ' + + 'Please use `{{bind-attr}}`\'s `:static-class` syntax instead.', + !element.getAttribute('class') + ); + + view.appendChild(classView); + } + + var attrKeys = keys(hash); + + var attr, path, lazyValue, attrView; + for (var i=0, l=attrKeys.length;i` the following template: + + ```handlebars + {{! application.hbs }} + {{#collection content=model}} + Hi {{view.content.name}} + {{/collection}} + ``` + + And the following application code + + ```javascript + App = Ember.Application.create(); + App.ApplicationRoute = Ember.Route.extend({ + model: function(){ + return [{name: 'Yehuda'},{name: 'Tom'},{name: 'Peter'}]; + } + }); + ``` + + The following HTML will result: + + ```html +
+
Hi Yehuda
+
Hi Tom
+
Hi Peter
+
+ ``` + + ### Non-block version of collection + + If you provide an `itemViewClass` option that has its own `template` you may + omit the block. + + The following template: + + ```handlebars + {{! application.hbs }} + {{collection content=model itemViewClass="an-item"}} + ``` + + And application code + + ```javascript + App = Ember.Application.create(); + App.ApplicationRoute = Ember.Route.extend({ + model: function(){ + return [{name: 'Yehuda'},{name: 'Tom'},{name: 'Peter'}]; + } + }); + + App.AnItemView = Ember.View.extend({ + template: Ember.Handlebars.compile("Greetings {{view.content.name}}") + }); + ``` + + Will result in the HTML structure below + + ```html +
+
Greetings Yehuda
+
Greetings Tom
+
Greetings Peter
+
+ ``` + + ### Specifying a CollectionView subclass + + By default the `{{collection}}` helper will create an instance of + `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to + the helper by passing it as the first argument: + + ```handlebars + {{#collection "my-custom-collection" content=model}} + Hi {{view.content.name}} + {{/collection}} + ``` + + This example would look for the class `App.MyCustomCollection`. + + ### Forwarded `item.*`-named Options + + As with the `{{view}}`, helper options passed to the `{{collection}}` will be + set on the resulting `Ember.CollectionView` as properties. Additionally, + options prefixed with `item` will be applied to the views rendered for each + item (note the camelcasing): + + ```handlebars + {{#collection content=model + itemTagName="p" + itemClassNames="greeting"}} + Howdy {{view.content.name}} + {{/collection}} + ``` + + Will result in the following HTML structure: + + ```html +
+

Howdy Yehuda

+

Howdy Tom

+

Howdy Peter

+
+ ``` + + @method collection + @for Ember.Handlebars.helpers + @param {String} path + @param {Hash} options + @return {String} HTML string + @deprecated Use `{{each}}` helper instead. + */ + function collectionHelper(params, hash, options, env) { + var path = params[0]; + + Ember.deprecate("Using the {{collection}} helper without specifying a class has been" + + " deprecated as the {{each}} helper now supports the same functionality.", path !== 'collection'); + + Ember.assert("You cannot pass more than one argument to the collection helper", params.length <= 1); + + var data = env.data; + var template = options.template; + var inverse = options.inverse; + var view = data.view; + + // This should be deterministic, and should probably come from a + // parent view and not the controller. + var controller = get(view, 'controller'); + var container = (controller && controller.container ? controller.container : view.container); + + // If passed a path string, convert that into an object. + // Otherwise, just default to the standard class. + var collectionClass; + if (path) { + collectionClass = readViewFactory(path, container); + Ember.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass); + } + else { + collectionClass = CollectionView; + } + + var itemHash = {}; + var match; + + // Extract item view class if provided else default to the standard class + var collectionPrototype = collectionClass.proto(); + var itemViewClass; + + if (hash.itemView) { + itemViewClass = readViewFactory(hash.itemView, container); + } else if (hash.itemViewClass) { + itemViewClass = readViewFactory(hash.itemViewClass, container); + } else { + itemViewClass = collectionPrototype.itemViewClass; + } + + if (typeof itemViewClass === 'string') { + itemViewClass = container.lookupFactory('view:'+itemViewClass); + } + + Ember.assert(fmt("%@ #collection: Could not find itemViewClass %@", [data.view, itemViewClass]), !!itemViewClass); + + delete hash.itemViewClass; + delete hash.itemView; + + // Go through options passed to the {{collection}} helper and extract options + // that configure item views instead of the collection itself. + for (var prop in hash) { + if (prop === 'itemController' || prop === 'itemClassBinding') { + continue; + } + if (hash.hasOwnProperty(prop)) { + match = prop.match(/^item(.)(.*)$/); + if (match) { + var childProp = match[1].toLowerCase() + match[2]; + + if (IS_BINDING.test(prop)) { + itemHash[childProp] = view._getBindingForStream(hash[prop]); + } else { + itemHash[childProp] = hash[prop]; + } + delete hash[prop]; + } + } + } + + if (template) { + itemHash.template = template; + delete options.template; + } + + var emptyViewClass; + if (inverse) { + emptyViewClass = get(collectionPrototype, 'emptyViewClass'); + emptyViewClass = emptyViewClass.extend({ + template: inverse, + tagName: itemHash.tagName + }); + } else if (hash.emptyViewClass) { + emptyViewClass = readViewFactory(hash.emptyViewClass, container); + } + if (emptyViewClass) { hash.emptyView = emptyViewClass; } + + if (hash.keyword) { + itemHash._contextBinding = Binding.oneWay('_parentView.context'); + } else { + itemHash._contextBinding = Binding.oneWay('content'); + } + + var viewOptions = ViewHelper.propertiesFromHTMLOptions(itemHash, {}, { data: data }); + + if (hash.itemClassBinding) { + var itemClassBindings = hash.itemClassBinding.split(' '); + viewOptions.classNameBindings = map(itemClassBindings, function(classBinding){ + return streamifyClassNameBinding(view, classBinding); + }); + } + + hash.itemViewClass = itemViewClass; + hash._itemViewProps = viewOptions; + + options.helperName = options.helperName || 'collection'; + + return env.helpers.view.helperFunction.call(this, [collectionClass], hash, options, env); + } + + __exports__.collectionHelper = collectionHelper; + }); +enifed("ember-htmlbars/helpers/debugger", + ["ember-metal/logger","exports"], function(__dependency1__, __exports__) { "use strict"; - var EmberObject = __dependency1__["default"]; + /*jshint debug:true*/ - __exports__["default"] = EmberObject.extend({ - lookupFactory: function(name, container) { + /** + @module ember + @submodule ember-htmlbars + */ + var Logger = __dependency1__["default"]; - container = container || this.container; + /** + Execute the `debugger` statement in the current context. - var fullName = 'component:' + name; - var templateFullName = 'template:components/' + name; - var templateRegistered = container && container.has(templateFullName); + ```handlebars + {{debugger}} + ``` - if (templateRegistered) { - container.injection(fullName, 'layout', templateFullName); - } + Before invoking the `debugger` statement, there + are a few helpful variables defined in the + body of this helper that you can inspect while + debugging that describe how and where this + helper was invoked: - var Component = container.lookupFactory(fullName); + - templateContext: this is most likely a controller + from which this template looks up / displays properties + - typeOfTemplateContext: a string description of + what the templateContext is - // Only treat as a component if either the component - // or a template has been registered. - if (templateRegistered || Component) { - if (!Component) { - container.register(fullName, Ember.Component); - Component = container.lookupFactory(fullName); - } - return Component; - } - } - }); + For example, if you're wondering why a value `{{foo}}` + isn't rendering as expected within a template, you + could place a `{{debugger}}` statement, and when + the `debugger;` breakpoint is hit, you can inspect + `templateContext`, determine if it's the object you + expect, and/or evaluate expressions in the console + to perform property lookups on the `templateContext`: + + ``` + > templateContext.get('foo') // -> "" + ``` + + @method debugger + @for Ember.Handlebars.helpers + @param {String} property + */ + function debuggerHelper() { + + // These are helpful values you can inspect while debugging. + /* jshint unused: false */ + var view = this; + Logger.info('Use `this` to access the view context.'); + + debugger; + } + + __exports__.debuggerHelper = debuggerHelper; }); -enifed("ember-handlebars/controls", - ["ember-handlebars/controls/checkbox","ember-handlebars/controls/text_field","ember-handlebars/controls/text_area","ember-metal/core","ember-handlebars-compiler","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { +enifed("ember-htmlbars/helpers/each", + ["ember-metal/core","ember-views/views/each","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + + /** + @module ember + @submodule ember-htmlbars + */ + var Ember = __dependency1__["default"]; + // Ember.assert; + var EachView = __dependency2__["default"]; + + /** + The `{{#each}}` helper loops over elements in a collection. It is an extension + of the base Handlebars `{{#each}}` helper. + + The default behavior of `{{#each}}` is to yield its inner block once for every + item in an array. + + ```javascript + var developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}]; + ``` + + ```handlebars + {{#each person in developers}} + {{person.name}} + {{! `this` is whatever it was outside the #each }} + {{/each}} + ``` + + The same rules apply to arrays of primitives, but the items may need to be + references with `{{this}}`. + + ```javascript + var developerNames = ['Yehuda', 'Tom', 'Paul'] + ``` + + ```handlebars + {{#each name in developerNames}} + {{name}} + {{/each}} + ``` + + ### {{else}} condition + + `{{#each}}` can have a matching `{{else}}`. The contents of this block will render + if the collection is empty. + + ``` + {{#each person in developers}} + {{person.name}} + {{else}} +

Sorry, nobody is available for this task.

+ {{/each}} + ``` + + ### Specifying an alternative view for each item + + `itemViewClass` can control which view will be used during the render of each + item's template. + + The following template: + + ```handlebars +
    + {{#each developer in developers itemViewClass="person"}} + {{developer.name}} + {{/each}} +
+ ``` + + Will use the following view for each item + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li' + }); + ``` + + Resulting in HTML output that looks like the following: + + ```html +
    +
  • Yehuda
  • +
  • Tom
  • +
  • Paul
  • +
+ ``` + + `itemViewClass` also enables a non-block form of `{{each}}`. The view + must {{#crossLink "Ember.View/toc_templates"}}provide its own template{{/crossLink}}, + and then the block should be dropped. An example that outputs the same HTML + as the previous one: + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li', + template: '{{developer.name}}' + }); + ``` + + ```handlebars +
    + {{each developer in developers itemViewClass="person"}} +
+ ``` + + ### Specifying an alternative view for no items (else) + + The `emptyViewClass` option provides the same flexibility to the `{{else}}` + case of the each helper. + + ```javascript + App.NoPeopleView = Ember.View.extend({ + tagName: 'li', + template: 'No person is available, sorry' + }); + ``` + + ```handlebars +
    + {{#each developer in developers emptyViewClass="no-people"}} +
  • {{developer.name}}
  • + {{/each}} +
+ ``` + + ### Wrapping each item in a controller + + Controllers in Ember manage state and decorate data. In many cases, + providing a controller for each item in a list can be useful. + Specifically, an {{#crossLink "Ember.ObjectController"}}Ember.ObjectController{{/crossLink}} + should probably be used. Item controllers are passed the item they + will present as a `model` property, and an object controller will + proxy property lookups to `model` for us. + + This allows state and decoration to be added to the controller + while any other property lookups are delegated to the model. An example: + + ```javascript + App.RecruitController = Ember.ObjectController.extend({ + isAvailableForHire: function() { + return !this.get('isEmployed') && this.get('isSeekingWork'); + }.property('isEmployed', 'isSeekingWork') + }) + ``` + + ```handlebars + {{#each person in developers itemController="recruit"}} + {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}} + {{/each}} + ``` + + @method each + @for Ember.Handlebars.helpers + @param [name] {String} name for item (used with `in`) + @param [path] {String} path + @param [options] {Object} Handlebars key/value pairs of options + @param [options.itemViewClass] {String} a path to a view class used for each item + @param [options.emptyViewClass] {String} a path to a view class used for each item + @param [options.itemController] {String} name of a controller to be created for each item + */ + function eachHelper(params, hash, options, env) { + var helperName = 'each'; + var path = params[0] || this.getStream(''); + + Ember.assert( + "If you pass more than one argument to the each helper, " + + "it must be in the form #each foo in bar", + params.length <= 1 + ); + + if (options.template && options.template.blockParams) { + hash.keyword = true; + } + + Ember.deprecate( + "Using the context switching form of {{each}} is deprecated. " + + "Please use the keyword form (`{{#each foo in bar}}`) instead.", + hash.keyword === true || typeof hash.keyword === 'string', + { url: 'http://emberjs.com/guides/deprecations/#toc_more-consistent-handlebars-scope' } + ); + + hash.dataSource = path; + options.helperName = options.helperName || helperName; + + return env.helpers.collection.helperFunction.call(this, [EachView], hash, options, env); + } + + __exports__.EachView = EachView; + __exports__.eachHelper = eachHelper; + }); +enifed("ember-htmlbars/helpers/if_unless", + ["ember-metal/core","ember-htmlbars/helpers/binding","ember-metal/property_get","ember-metal/utils","ember-views/streams/conditional_stream","ember-metal/streams/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-htmlbars + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var bind = __dependency2__.bind; + + var get = __dependency3__.get; + var isArray = __dependency4__.isArray; + var ConditionalStream = __dependency5__["default"]; + var isStream = __dependency6__.isStream; + + function shouldDisplayIfHelperContent(result) { + var truthy = result && get(result, 'isTruthy'); + if (typeof truthy === 'boolean') { return truthy; } + + if (isArray(result)) { + return get(result, 'length') !== 0; + } else { + return !!result; + } + } + + var EMPTY_TEMPLATE = { + isHTMLBars: true, + render: function() { + return ''; + } + }; + /** + Use the `boundIf` helper to create a conditional that re-evaluates + whenever the truthiness of the bound value changes. + + ```handlebars + {{#boundIf "content.shouldDisplayTitle"}} + {{content.title}} + {{/boundIf}} + ``` + + @private + @method boundIf + @for Ember.Handlebars.helpers + @param {String} property Property to bind + @param {Function} fn Context to provide for rendering + @return {String} HTML string + */ + function boundIfHelper(params, hash, options, env) { + options.helperName = options.helperName || 'boundIf'; + return bind.call(this, params[0], hash, options, env, true, shouldDisplayIfHelperContent, shouldDisplayIfHelperContent, [ + 'isTruthy', + 'length' + ]); + } + + /** + @private + + Use the `unboundIf` helper to create a conditional that evaluates once. + + ```handlebars + {{#unboundIf "content.shouldDisplayTitle"}} + {{content.title}} + {{/unboundIf}} + ``` + + @method unboundIf + @for Ember.Handlebars.helpers + @param {String} property Property to bind + @param {Function} fn Context to provide for rendering + @return {String} HTML string + @since 1.4.0 + */ + function unboundIfHelper(params, hash, options, env) { + var template = options.template; + var value = params[0]; + + if (isStream(params[0])) { + value = params[0].value(); + } + + if (!shouldDisplayIfHelperContent(value)) { + template = options.inverse || EMPTY_TEMPLATE; + } + + return template.render(this, env, options.morph.contextualElement); + } + + function _inlineIfAssertion(params) { + Ember.assert("If helper in inline form expects between two and three arguments", params.length === 2 || params.length === 3); + } + + /** + See [boundIf](/api/classes/Ember.Handlebars.helpers.html#method_boundIf) + and [unboundIf](/api/classes/Ember.Handlebars.helpers.html#method_unboundIf) + + @method if + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function ifHelper(params, hash, options, env) { + Ember.assert("If helper in block form expect exactly one argument", !options.template || params.length === 1); + + options.inverse = options.inverse || EMPTY_TEMPLATE; + + options.helperName = options.helperName || ('if '); + + if (env.data.isUnbound) { + env.data.isUnbound = false; + return env.helpers.unboundIf.helperFunction.call(this, params, hash, options, env); + } else { + return env.helpers.boundIf.helperFunction.call(this, params, hash, options, env); + } + } + + /** + @method unless + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function unlessHelper(params, hash, options, env) { + Ember.assert("You must pass exactly one argument to the unless helper", params.length === 1); + Ember.assert("You must pass a block to the unless helper", !!options.template); + + var template = options.template; + var inverse = options.inverse || EMPTY_TEMPLATE; + var helperName = 'unless'; + + options.template = inverse; + options.inverse = template; + + options.helperName = options.helperName || helperName; + + if (env.data.isUnbound) { + env.data.isUnbound = false; + return env.helpers.unboundIf.helperFunction.call(this, params, hash, options, env); + } else { + return env.helpers.boundIf.helperFunction.call(this, params, hash, options, env); + } + } + + __exports__.ifHelper = ifHelper; + __exports__.boundIfHelper = boundIfHelper; + __exports__.unboundIfHelper = unboundIfHelper; + __exports__.unlessHelper = unlessHelper; + }); +enifed("ember-htmlbars/helpers/input", + ["ember-views/views/checkbox","ember-views/views/text_field","ember-metal/streams/utils","ember-metal/core","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; var Checkbox = __dependency1__["default"]; var TextField = __dependency2__["default"]; - var TextArea = __dependency3__["default"]; + var read = __dependency3__.read; var Ember = __dependency4__["default"]; // Ember.assert - // var emberAssert = Ember.assert; - - var EmberHandlebars = __dependency5__["default"]; /** @module ember - @submodule ember-handlebars-compiler + @submodule ember-htmlbars */ /** @@ -5262,12 +6489,10 @@ enifed("ember-handlebars/controls", The action property defines the action which is sent when the user presses the return key. - ```handlebars {{input action="submit"}} ``` - The helper allows some user events to send actions. * `enter` @@ -5281,12 +6506,10 @@ enifed("ember-handlebars/controls", For example, if you desire an action to be sent when the input is blurred, you only need to setup the action name to the event name property. - ```handlebars {{input focus-in="alertMessage"}} ``` - See more about [Text Support Actions](/api/classes/Ember.TextField.html) ## Extension @@ -5376,38 +6599,274 @@ enifed("ember-handlebars/controls", @for Ember.Handlebars.helpers @param {Hash} options */ - function inputHelper(options) { - Ember.assert('You can only pass attributes to the `input` helper, not arguments', arguments.length < 2); + function inputHelper(params, hash, options, env) { + Ember.assert('You can only pass attributes to the `input` helper, not arguments', params.length === 0); - var view = options.data.view; - var hash = options.hash; - var types = options.hashTypes; var onEvent = hash.on; var inputType; - if (types.type === 'ID') { - inputType = view.getStream(hash.type).value(); - } else { - inputType = hash.type; - } + inputType = read(hash.type); if (inputType === 'checkbox') { delete hash.type; - delete types.type; Ember.assert("{{input type='checkbox'}} does not support setting `value=someBooleanValue`;" + - " you must use `checked=someBooleanValue` instead.", options.hashTypes.value !== 'ID'); + " you must use `checked=someBooleanValue` instead.", !hash.hasOwnProperty('value')); - return EmberHandlebars.helpers.view.call(this, Checkbox, options); + env.helpers.view.helperFunction.call(this, [Checkbox], hash, options, env); } else { delete hash.on; hash.onEvent = onEvent || 'enter'; - return EmberHandlebars.helpers.view.call(this, TextField, options); + env.helpers.view.helperFunction.call(this, [TextField], hash, options, env); } } - __exports__.inputHelper = inputHelper;/** + __exports__.inputHelper = inputHelper; + }); +enifed("ember-htmlbars/helpers/loc", + ["ember-metal/core","ember-runtime/system/string","ember-metal/streams/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var loc = __dependency2__.loc; + var isStream = __dependency3__.isStream; + + /** + @module ember + @submodule ember-htmlbars + */ + + /** + Calls [Ember.String.loc](/api/classes/Ember.String.html#method_loc) with the + provided string. + + This is a convenient way to localize text within a template: + + ```javascript + Ember.STRINGS = { + '_welcome_': 'Bonjour' + }; + ``` + + ```handlebars +
+ {{loc '_welcome_'}} +
+ ``` + + ```html +
+ Bonjour +
+ ``` + + See [Ember.String.loc](/api/classes/Ember.String.html#method_loc) for how to + set up localized string references. + + @method loc + @for Ember.Handlebars.helpers + @param {String} str The string to format + @see {Ember.String#loc} + */ + function locHelper(params, hash, options, env) { + Ember.assert('You cannot pass bindings to `loc` helper', (function ifParamsContainBindings() { + for (var i = 0, l = params.length; i < l; i++) { + if (isStream(params[i])) { + return false; + } + } + return true; + })()); + + return loc.apply(this, params); + } + + __exports__.locHelper = locHelper; + }); +enifed("ember-htmlbars/helpers/log", + ["ember-metal/logger","ember-metal/streams/utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-htmlbars + */ + var Logger = __dependency1__["default"]; + var read = __dependency2__.read; + + /** + `log` allows you to output the value of variables in the current rendering + context. `log` also accepts primitive types such as strings or numbers. + + ```handlebars + {{log "myVariable:" myVariable }} + ``` + + @method log + @for Ember.Handlebars.helpers + @param {String} property + */ + function logHelper(params, hash, options, env) { + var logger = Logger.log; + var values = []; + + for (var i = 0; i < params.length; i++) { + values.push(read(params[i])); + } + + logger.apply(logger, values); + } + + __exports__.logHelper = logHelper; + }); +enifed("ember-htmlbars/helpers/partial", + ["ember-metal/core","ember-metal/is_none","./binding","ember-metal/streams/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + + var isNone = __dependency2__["default"]; + var bind = __dependency3__.bind; + var isStream = __dependency4__.isStream; + + /** + @module ember + @submodule ember-htmlbars + */ + + /** + The `partial` helper renders another template without + changing the template context: + + ```handlebars + {{foo}} + {{partial "nav"}} + ``` + + The above example template will render a template named + "_nav", which has the same context as the parent template + it's rendered into, so if the "_nav" template also referenced + `{{foo}}`, it would print the same thing as the `{{foo}}` + in the above example. + + If a "_nav" template isn't found, the `partial` helper will + fall back to a template named "nav". + + ## Bound template names + + The parameter supplied to `partial` can also be a path + to a property containing a template name, e.g.: + + ```handlebars + {{partial someTemplateName}} + ``` + + The above example will look up the value of `someTemplateName` + on the template context (e.g. a controller) and use that + value as the name of the template to render. If the resolved + value is falsy, nothing will be rendered. If `someTemplateName` + changes, the partial will be re-rendered using the new template + name. + + + @method partial + @for Ember.Handlebars.helpers + @param {String} partialName the name of the template to render minus the leading underscore + */ + + function partialHelper(params, hash, options, env) { + options.helperName = options.helperName || 'partial'; + + var name = params[0]; + + if (isStream(name)) { + options.template = createPartialTemplate(name); + bind.call(this, name, hash, options, env, true, exists); + } else { + return renderPartial(name, this, env, options.morph.contextualElement); + } + } + + __exports__.partialHelper = partialHelper;function exists(value) { + return !isNone(value); + } + + function lookupPartial(view, templateName) { + var nameParts = templateName.split("/"); + var lastPart = nameParts[nameParts.length - 1]; + + nameParts[nameParts.length - 1] = "_" + lastPart; + + var underscoredName = nameParts.join('/'); + var template = view.templateForName(underscoredName); + if (!template) { + template = view.templateForName(templateName); + } + + Ember.assert('Unable to find partial with name "'+templateName+'"', !!template); + + return template; + } + + function renderPartial(name, view, env, contextualElement) { + var template = lookupPartial(view, name); + return template.render(view, env, contextualElement); + } + + function createPartialTemplate(nameStream) { + return { + isHTMLBars: true, + render: function(view, env, contextualElement) { + return renderPartial(nameStream.value(), view, env, contextualElement); + } + }; + } + }); +enifed("ember-htmlbars/helpers/template", + ["ember-metal/core","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.deprecate; + + /** + @module ember + @submodule ember-htmlbars + */ + + /** + @deprecated + @method template + @for Ember.Handlebars.helpers + @param {String} templateName the template to render + */ + function templateHelper(params, hash, options, env) { + Ember.deprecate("The `template` helper has been deprecated in favor of the `partial` helper." + + " Please use `partial` instead, which will work the same way."); + + options.helperName = options.helperName || 'template'; + + return env.helpers.partial.helperFunction.call(this, params, hash, options, env); + } + + __exports__.templateHelper = templateHelper; + }); +enifed("ember-htmlbars/helpers/text_area", + ["ember-metal/core","ember-views/views/text_area","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-htmlbars + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var TextArea = __dependency2__["default"]; + + /** `{{textarea}}` inserts a new instance of ` - ``` - - Bound: - - In the following example, the `writtenWords` property on `App.ApplicationController` - will be updated live as the user types 'Lots of text that IS bound' into - the text area of their browser's window. - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - writtenWords: "Lots of text that IS bound" - }); - ``` - - ```handlebars - {{textarea value=writtenWords}} - ``` - - Would result in the following HTML: - - ```html - - ``` - - If you wanted a one way binding between the text area and a div tag - somewhere else on your screen, you could use `Ember.computed.oneWay`: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - writtenWords: "Lots of text that IS bound", - outputWrittenWords: Ember.computed.oneWay("writtenWords") - }); - ``` - - ```handlebars - {{textarea value=writtenWords}} - -
- {{outputWrittenWords}} -
- ``` - - Would result in the following HTML: - - ```html - - - <-- the following div will be updated in real time as you type --> - -
- Lots of text that IS bound -
- ``` - - Finally, this example really shows the power and ease of Ember when two - properties are bound to eachother via `Ember.computed.alias`. Type into - either text area box and they'll both stay in sync. Note that - `Ember.computed.alias` costs more in terms of performance, so only use it when - your really binding in both directions: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - writtenWords: "Lots of text that IS bound", - twoWayWrittenWords: Ember.computed.alias("writtenWords") - }); - ``` - - ```handlebars - {{textarea value=writtenWords}} - {{textarea value=twoWayWrittenWords}} - ``` - - ```html - - - <-- both updated in real time --> - - - ``` - - ## Actions - - The helper can send multiple actions based on user events. - - The action property defines the action which is send when - the user presses the return key. - - ```handlebars - {{input action="submit"}} - ``` - - The helper allows some user events to send actions. - - * `enter` - * `insert-newline` - * `escape-press` - * `focus-in` - * `focus-out` - * `key-press` - - For example, if you desire an action to be sent when the input is blurred, - you only need to setup the action name to the event name property. - - ```handlebars - {{textarea focus-in="alertMessage"}} - ``` - - See more about [Text Support Actions](/api/classes/Ember.TextArea.html) - - ## Extension - - Internally, `{{textarea}}` creates an instance of `Ember.TextArea`, passing - arguments from the helper to `Ember.TextArea`'s `create` method. You can - extend the capabilities of text areas in your application by reopening this - class. For example, if you are building a Bootstrap project where `data-*` - attributes are used, you can globally add support for a `data-*` attribute - on all `{{textarea}}`s' in your app by reopening `Ember.TextArea` or - `Ember.TextSupport` and adding it to the `attributeBindings` concatenated - property: - - ```javascript - Ember.TextArea.reopen({ - attributeBindings: ['data-error'] - }); - ``` - - Keep in mind when writing `Ember.TextArea` subclasses that `Ember.TextArea` - itself extends `Ember.Component`, meaning that it does NOT inherit - the `controller` of the parent view. - - See more about [Ember components](/api/classes/Ember.Component.html) - - @method textarea - @for Ember.Handlebars.helpers - @param {Hash} options - */ - function textareaHelper(params, hash, options, env) { - Ember.assert('You can only pass attributes to the `textarea` helper, not arguments', params.length === 0); - - return env.helpers.view.helperFunction.call(this, [TextArea], hash, options, env); - } - - __exports__.textareaHelper = textareaHelper; - }); -enifed("ember-htmlbars/helpers/unbound", - ["ember-htmlbars/system/lookup-helper","ember-metal/streams/utils","ember-metal/error","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var lookupHelper = __dependency1__["default"]; - var read = __dependency2__.read; - var EmberError = __dependency3__["default"]; - - /** - @module ember - @submodule ember-htmlbars - */ - - /** - `unbound` allows you to output a property without binding. *Important:* The - output will not be updated if the property changes. Use with caution. - - ```handlebars -
{{unbound somePropertyThatDoesntChange}}
- ``` - - `unbound` can also be used in conjunction with a bound helper to - render it in its unbound form: - - ```handlebars -
{{unbound helperName somePropertyThatDoesntChange}}
- ``` - - @method unbound - @for Ember.Handlebars.helpers - @param {String} property - @return {String} HTML string - */ - function unboundHelper(params, hash, options, env) { - var length = params.length; - var result; - - options.helperName = options.helperName || 'unbound'; - - if (length === 1) { - result = read(params[0]); - } else if (length >= 2) { - env.data.isUnbound = true; - - var helperName = params[0]._label; - var args = []; - - for (var i = 1, l = params.length; i < l; i++) { - var value = read(params[i]); - - args.push(value); - } - - var helper = lookupHelper(helperName, this, env); - - if (!helper) { - throw new EmberError('HTMLBars error: Could not find component or helper named ' + helperName + '.'); - } - - result = helper.helperFunction.call(this, args, hash, options, env); - - delete env.data.isUnbound; - } - - return result; - } - - __exports__.unboundHelper = unboundHelper; - }); -enifed("ember-htmlbars/helpers/view", - ["ember-metal/core","ember-runtime/system/object","ember-metal/property_get","ember-metal/streams/simple","ember-metal/keys","ember-metal/mixin","ember-metal/streams/utils","ember-views/streams/utils","ember-views/views/view","ember-metal/enumerable_utils","ember-views/streams/class_name_binding","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var Ember = __dependency1__["default"]; - // Ember.warn, Ember.assert - var EmberObject = __dependency2__["default"]; - var get = __dependency3__.get; - var SimpleStream = __dependency4__["default"]; - var keys = __dependency5__["default"]; - var IS_BINDING = __dependency6__.IS_BINDING; - var read = __dependency7__.read; - var isStream = __dependency7__.isStream; - var readViewFactory = __dependency8__.readViewFactory; - var View = __dependency9__["default"]; - - var map = __dependency10__.map; - var streamifyClassNameBinding = __dependency11__.streamifyClassNameBinding; - - function makeBindings(hash, options, view) { - for (var prop in hash) { - var value = hash[prop]; - - // Classes are processed separately - if (prop === 'class' && isStream(value)) { - hash.classBinding = value._label; - delete hash['class']; - continue; - } - - if (prop === 'classBinding') { - continue; - } - - if (IS_BINDING.test(prop)) { - if (isStream(value)) { - Ember.warn("You're attempting to render a view by passing " + - prop + " " + - "to a view helper without a quoted value, " + - "but this syntax is ambiguous. You should either surround " + - prop + "'s value in quotes or remove `Binding` " + - "from " + prop + "."); - } else if (typeof value === 'string') { - hash[prop] = view._getBindingForStream(value); - } - } else { - if (isStream(value) && prop !== 'id') { - hash[prop + 'Binding'] = view._getBindingForStream(value); - delete hash[prop]; - } - } - } - } - - var ViewHelper = EmberObject.create({ - propertiesFromHTMLOptions: function(hash, options, env) { - var view = env.data.view; - var classes = read(hash['class']); - - var extensions = { - helperName: options.helperName || '' - }; - - if (hash.id) { - extensions.elementId = read(hash.id); - } - - if (hash.tag) { - extensions.tagName = hash.tag; - } - - if (classes) { - classes = classes.split(' '); - extensions.classNames = classes; - } - - if (hash.classBinding) { - extensions.classNameBindings = hash.classBinding.split(' '); - } - - if (hash.classNameBindings) { - if (extensions.classNameBindings === undefined) { - extensions.classNameBindings = []; - } - extensions.classNameBindings = extensions.classNameBindings.concat(hash.classNameBindings.split(' ')); - } - - if (hash.attributeBindings) { - Ember.assert("Setting 'attributeBindings' via template helpers is not allowed." + - " Please subclass Ember.View and set it there instead."); - extensions.attributeBindings = null; - } - - // Set the proper context for all bindings passed to the helper. This applies to regular attribute bindings - // as well as class name bindings. If the bindings are local, make them relative to the current context - // instead of the view. - - var hashKeys = keys(hash); - - for (var i = 0, l = hashKeys.length; i < l; i++) { - var prop = hashKeys[i]; - - if (prop !== 'classNameBindings') { - extensions[prop] = hash[prop]; - } - } - - if (extensions.classNameBindings) { - extensions.classNameBindings = map(extensions.classNameBindings, function(classNameBinding){ - var binding = streamifyClassNameBinding(view, classNameBinding); - if (isStream(binding)) { - return binding; - } else { - // returning a stream informs the classNameBindings logic - // in views/view that this value is already processed. - return new SimpleStream(binding); - } - }); - } - - return extensions; - }, - - helper: function(newView, hash, options, env) { - var data = env.data; - var template = options.template; - var newViewProto; - - makeBindings(hash, options, env.data.view); - - var viewOptions = this.propertiesFromHTMLOptions(hash, options, env); - var currentView = data.view; - - if (View.detectInstance(newView)) { - newViewProto = newView; - } else { - newViewProto = newView.proto(); - } - - if (template) { - Ember.assert( - "You cannot provide a template block if you also specified a templateName", - !get(viewOptions, 'templateName') && !get(newViewProto, 'templateName') - ); - viewOptions.template = template; - } - - // We only want to override the `_context` computed property if there is - // no specified controller. See View#_context for more information. - if (!newViewProto.controller && !newViewProto.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) { - viewOptions._context = get(currentView, 'context'); // TODO: is this right?! - } - - viewOptions._morph = options.morph; - - currentView.appendChild(newView, viewOptions); - }, - - instanceHelper: function(newView, hash, options, env) { - var data = env.data; - var template = options.template; - - makeBindings(hash, options, env.data.view); - - Ember.assert( - 'Only a instance of a view may be passed to the ViewHelper.instanceHelper', - View.detectInstance(newView) - ); - - var viewOptions = this.propertiesFromHTMLOptions(hash, options, env); - var currentView = data.view; - - if (template) { - Ember.assert( - "You cannot provide a template block if you also specified a templateName", - !get(viewOptions, 'templateName') && !get(newView, 'templateName') - ); - viewOptions.template = template; - } - - // We only want to override the `_context` computed property if there is - // no specified controller. See View#_context for more information. - if (!newView.controller && !newView.controllerBinding && - !viewOptions.controller && !viewOptions.controllerBinding) { - viewOptions._context = get(currentView, 'context'); // TODO: is this right?! - } - - viewOptions._morph = options.morph; - - currentView.appendChild(newView, viewOptions); - } - }); - __exports__.ViewHelper = ViewHelper; - /** - `{{view}}` inserts a new instance of an `Ember.View` into a template passing its - options to the `Ember.View`'s `create` method and using the supplied block as - the view's own template. - - An empty `` and the following template: - - ```handlebars - A span: - {{#view tagName="span"}} - hello. - {{/view}} - ``` - - Will result in HTML structure: - - ```html - - - -
- A span: - - Hello. - -
- - ``` - - ### `parentView` setting - - The `parentView` property of the new `Ember.View` instance created through - `{{view}}` will be set to the `Ember.View` instance of the template where - `{{view}}` was called. - - ```javascript - aView = Ember.View.create({ - template: Ember.Handlebars.compile("{{#view}} my parent: {{parentView.elementId}} {{/view}}") - }); - - aView.appendTo('body'); - ``` - - Will result in HTML structure: - - ```html -
-
- my parent: ember1 -
-
- ``` - - ### Setting CSS id and class attributes - - The HTML `id` attribute can be set on the `{{view}}`'s resulting element with - the `id` option. This option will _not_ be passed to `Ember.View.create`. - - ```handlebars - {{#view tagName="span" id="a-custom-id"}} - hello. - {{/view}} - ``` - - Results in the following HTML structure: - - ```html -
- - hello. - -
- ``` - - The HTML `class` attribute can be set on the `{{view}}`'s resulting element - with the `class` or `classNameBindings` options. The `class` option will - directly set the CSS `class` attribute and will not be passed to - `Ember.View.create`. `classNameBindings` will be passed to `create` and use - `Ember.View`'s class name binding functionality: - - ```handlebars - {{#view tagName="span" class="a-custom-class"}} - hello. - {{/view}} - ``` - - Results in the following HTML structure: - - ```html -
- - hello. - -
- ``` - - ### Supplying a different view class - - `{{view}}` can take an optional first argument before its supplied options to - specify a path to a custom view class. - - ```handlebars - {{#view "custom"}}{{! will look up App.CustomView }} - hello. - {{/view}} - ``` - - The first argument can also be a relative path accessible from the current - context. - - ```javascript - MyApp = Ember.Application.create({}); - MyApp.OuterView = Ember.View.extend({ - innerViewClass: Ember.View.extend({ - classNames: ['a-custom-view-class-as-property'] - }), - template: Ember.Handlebars.compile('{{#view view.innerViewClass}} hi {{/view}}') - }); - - MyApp.OuterView.create().appendTo('body'); - ``` - - Will result in the following HTML: - - ```html -
-
- hi -
-
- ``` - - ### Blockless use - - If you supply a custom `Ember.View` subclass that specifies its own template - or provide a `templateName` option to `{{view}}` it can be used without - supplying a block. Attempts to use both a `templateName` option and supply a - block will throw an error. - - ```javascript - var App = Ember.Application.create(); - App.WithTemplateDefinedView = Ember.View.extend({ - templateName: 'defined-template' - }); - ``` - - ```handlebars - {{! application.hbs }} - {{view 'with-template-defined'}} - ``` - - ```handlebars - {{! defined-template.hbs }} - Some content for the defined template view. - ``` - - ### `viewName` property - - You can supply a `viewName` option to `{{view}}`. The `Ember.View` instance - will be referenced as a property of its parent view by this name. - - ```javascript - aView = Ember.View.create({ - template: Ember.Handlebars.compile('{{#view viewName="aChildByName"}} hi {{/view}}') - }); - - aView.appendTo('body'); - aView.get('aChildByName') // the instance of Ember.View created by {{view}} helper - ``` - - @method view - @for Ember.Handlebars.helpers - @param {String} path - @param {Hash} options - @return {String} HTML string - */ - function viewHelper(params, hash, options, env) { - Ember.assert("The view helper only takes a single argument", params.length <= 2); - - var container = this.container || read(this._keywords.view).container; - var viewClass; - - if (params.length === 0) { - if (container) { - viewClass = container.lookupFactory('view:toplevel'); - } else { - viewClass = View; - } - } else { - var pathStream = params[0]; - viewClass = readViewFactory(pathStream, container); - } - - options.helperName = options.helperName || 'view'; - - return ViewHelper.helper(viewClass, hash, options, env); - } - - __exports__.viewHelper = viewHelper; - }); -enifed("ember-htmlbars/helpers/with", - ["ember-metal/core","ember-metal/is_none","ember-htmlbars/helpers/binding","ember-views/views/with_view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var isNone = __dependency2__["default"]; - var bind = __dependency3__.bind; - var WithView = __dependency4__["default"]; - - /** - Use the `{{with}}` helper when you want to aliases the to a new name. It's helpful - for semantic clarity and to retain default scope or to reference from another - `{{with}}` block. - - ```handlebars - // posts might not be - {{#with user.posts as blogPosts}} -
- There are {{blogPosts.length}} blog posts written by {{user.name}}. -
- - {{#each post in blogPosts}} -
  • {{post.title}}
  • - {{/each}} - {{/with}} - ``` - - Without the `as` operator, it would be impossible to reference `user.name` in the example above. - - NOTE: The alias should not reuse a name from the bound property path. - For example: `{{#with foo.bar as foo}}` is not supported because it attempts to alias using - the first part of the property path, `foo`. Instead, use `{{#with foo.bar as baz}}`. - - ### `controller` option - - Adding `controller='something'` instructs the `{{with}}` helper to create and use an instance of - the specified controller wrapping the aliased keyword. - - This is very similar to using an `itemController` option with the `{{each}}` helper. - - ```handlebars - {{#with users.posts as posts controller='userBlogPosts'}} - {{!- `posts` is wrapped in our controller instance }} - {{/with}} - ``` - - In the above example, the `posts` keyword is now wrapped in the `userBlogPost` controller, - which provides an elegant way to decorate the context with custom - functions/properties. - - @method with - @for Ember.Handlebars.helpers - @param {Function} context - @param {Hash} options - @return {String} HTML string - */ - function withHelper(params, hash, options, env) { - Ember.assert( - "{{#with foo}} must be called with a single argument or the use the " + - "{{#with foo as bar}} syntax", - params.length === 1 - ); - - Ember.assert( - "The {{#with}} helper must be called with a block", - !!options.template - ); - - var preserveContext; - - if (options.template.blockParams) { - preserveContext = true; - } else { - Ember.deprecate( - "Using the context switching form of `{{with}}` is deprecated. " + - "Please use the keyword form (`{{with foo as bar}}`) instead.", - false, - { url: 'http://emberjs.com/guides/deprecations/#toc_more-consistent-handlebars-scope' } - ); - preserveContext = false; - } - - bind.call(this, params[0], hash, options, env, preserveContext, exists, undefined, undefined, WithView); - } - - __exports__.withHelper = withHelper;function exists(value) { - return !isNone(value); - } - }); -enifed("ember-htmlbars/helpers/yield", - ["ember-metal/core","ember-metal/property_get","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var Ember = __dependency1__["default"]; - - var get = __dependency2__.get; - - /** - `{{yield}}` denotes an area of a template that will be rendered inside - of another template. It has two main uses: - - ### Use with `layout` - When used in a Handlebars template that is assigned to an `Ember.View` - instance's `layout` property Ember will render the layout template first, - inserting the view's own rendered output at the `{{yield}}` location. - - An empty `` and the following application code: - - ```javascript - AView = Ember.View.extend({ - classNames: ['a-view-with-layout'], - layout: Ember.Handlebars.compile('
    {{yield}}
    '), - template: Ember.Handlebars.compile('I am wrapped') - }); - - aView = AView.create(); - aView.appendTo('body'); - ``` - - Will result in the following HTML output: - - ```html - -
    -
    - I am wrapped -
    -
    - - ``` - - The `yield` helper cannot be used outside of a template assigned to an - `Ember.View`'s `layout` property and will throw an error if attempted. - - ```javascript - BView = Ember.View.extend({ - classNames: ['a-view-with-layout'], - template: Ember.Handlebars.compile('{{yield}}') - }); - - bView = BView.create(); - bView.appendTo('body'); - - // throws - // Uncaught Error: assertion failed: - // You called yield in a template that was not a layout - ``` - - ### Use with Ember.Component - When designing components `{{yield}}` is used to denote where, inside the component's - template, an optional block passed to the component should render: - - ```handlebars - - {{#labeled-textfield value=someProperty}} - First name: - {{/labeled-textfield}} - ``` - - ```handlebars - - - ``` - - Result: - - ```html - - ``` - - @method yield - @for Ember.Handlebars.helpers - @param {Hash} options - @return {String} HTML string - */ - function yieldHelper(params, hash, options, env) { - var view = this; - - // Yea gods - while (view && !get(view, 'layout')) { - if (view._contextView) { - view = view._contextView; - } else { - view = get(view, '_parentView'); - } - } - - Ember.assert("You called yield in a template that was not a layout", !!view); - - return view._yield(null, env, options.morph, params); - } - - __exports__.yieldHelper = yieldHelper; - }); -enifed("ember-htmlbars/hooks/attribute", - ["ember-views/attr_nodes/attr_node","ember-metal/error","ember-metal/streams/utils","ember-views/system/sanitize_attribute_value","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var AttrNode = __dependency1__["default"]; - var EmberError = __dependency2__["default"]; - var isStream = __dependency3__.isStream; - var sanitizeAttributeValue = __dependency4__["default"]; - - var boundAttributesEnabled = false; - - - __exports__["default"] = function attribute(env, morph, element, attrName, attrValue) { - if (boundAttributesEnabled) { - var attrNode = new AttrNode(attrName, attrValue); - attrNode._morph = morph; - env.data.view.appendChild(attrNode); - } else { - if (isStream(attrValue)) { - throw new EmberError('Bound attributes are not yet supported in Ember.js'); - } else { - var sanitizedValue = sanitizeAttributeValue(element, attrName, attrValue); - env.dom.setProperty(element, attrName, sanitizedValue); - } - } - } - }); -enifed("ember-htmlbars/hooks/block", - ["ember-views/views/simple_bound_view","ember-metal/streams/utils","ember-htmlbars/system/lookup-helper","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var appendSimpleBoundView = __dependency1__.appendSimpleBoundView; - var isStream = __dependency2__.isStream; - var lookupHelper = __dependency3__["default"]; - - __exports__["default"] = function block(env, morph, view, path, params, hash, template, inverse) { - var helper = lookupHelper(path, view, env); - - Ember.assert("A helper named `"+path+"` could not be found", helper); - - var options = { - morph: morph, - template: template, - inverse: inverse, - isBlock: true - }; - var result = helper.helperFunction.call(view, params, hash, options, env); - - if (isStream(result)) { - appendSimpleBoundView(view, morph, result); - } else { - morph.setContent(result); - } - } - }); -enifed("ember-htmlbars/hooks/component", - ["ember-metal/core","ember-htmlbars/system/lookup-helper","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var Ember = __dependency1__["default"]; - var lookupHelper = __dependency2__["default"]; - - __exports__["default"] = function component(env, morph, view, tagName, attrs, template) { - var helper = lookupHelper(tagName, view, env); - - Ember.assert('You specified `' + tagName + '` in your template, but a component for `' + tagName + '` could not be found.', !!helper); - - return helper.helperFunction.call(view, [], attrs, {morph: morph, template: template}, env); - } - }); -enifed("ember-htmlbars/hooks/concat", - ["ember-metal/streams/utils","exports"], - function(__dependency1__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var streamConcat = __dependency1__.concat; - - __exports__["default"] = function concat(env, parts) { - return streamConcat(parts, ''); - } - }); -enifed("ember-htmlbars/hooks/content", - ["ember-views/views/simple_bound_view","ember-metal/streams/utils","ember-htmlbars/system/lookup-helper","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var appendSimpleBoundView = __dependency1__.appendSimpleBoundView; - var isStream = __dependency2__.isStream; - var lookupHelper = __dependency3__["default"]; - - __exports__["default"] = function content(env, morph, view, path) { - var helper = lookupHelper(path, view, env); - var result; - - if (helper) { - var options = { - morph: morph, - isInline: true - }; - result = helper.helperFunction.call(view, [], {}, options, env); - } else { - result = view.getStream(path); - } - - if (isStream(result)) { - appendSimpleBoundView(view, morph, result); - } else { - morph.setContent(result); - } - } - }); -enifed("ember-htmlbars/hooks/element", - ["ember-metal/core","ember-metal/streams/utils","ember-htmlbars/system/lookup-helper","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var Ember = __dependency1__["default"]; - var read = __dependency2__.read; - var lookupHelper = __dependency3__["default"]; - - __exports__["default"] = function element(env, domElement, view, path, params, hash) { //jshint ignore:line - var helper = lookupHelper(path, view, env); - var valueOrLazyValue; - - if (helper) { - var options = { - element: domElement - }; - valueOrLazyValue = helper.helperFunction.call(view, params, hash, options, env); - } else { - valueOrLazyValue = view.getStream(path); - } - - var value = read(valueOrLazyValue); - if (value) { - Ember.deprecate('Returning a string of attributes from a helper inside an element is deprecated.'); - - var parts = value.toString().split(/\s+/); - for (var i = 0, l = parts.length; i < l; i++) { - var attrParts = parts[i].split('='); - var attrName = attrParts[0]; - var attrValue = attrParts[1]; - - attrValue = attrValue.replace(/^['"]/, '').replace(/['"]$/, ''); - - env.dom.setAttribute(domElement, attrName, attrValue); - } - } - } - }); -enifed("ember-htmlbars/hooks/get", - ["exports"], - function(__exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - __exports__["default"] = function get(env, view, path) { - return view.getStream(path); - } - }); -enifed("ember-htmlbars/hooks/inline", - ["ember-views/views/simple_bound_view","ember-metal/streams/utils","ember-htmlbars/system/lookup-helper","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var appendSimpleBoundView = __dependency1__.appendSimpleBoundView; - var isStream = __dependency2__.isStream; - var lookupHelper = __dependency3__["default"]; - - __exports__["default"] = function inline(env, morph, view, path, params, hash) { - var helper = lookupHelper(path, view, env); - - Ember.assert("A helper named '"+path+"' could not be found", helper); - - var result = helper.helperFunction.call(view, params, hash, {morph: morph}, env); - - if (isStream(result)) { - appendSimpleBoundView(view, morph, result); - } else { - morph.setContent(result); - } - } - }); -enifed("ember-htmlbars/hooks/set", - ["ember-metal/core","ember-metal/error","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var Ember = __dependency1__["default"]; - var EmberError = __dependency2__["default"]; - - __exports__["default"] = function set(env, view, name, value) { - - view._keywords[name] = value; - } - }); -enifed("ember-htmlbars/hooks/subexpr", - ["ember-htmlbars/system/lookup-helper","exports"], - function(__dependency1__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var lookupHelper = __dependency1__["default"]; - - __exports__["default"] = function subexpr(env, view, path, params, hash) { - var helper = lookupHelper(path, view, env); - - Ember.assert("A helper named '"+path+"' could not be found", helper); - - var options = { - isInline: true - }; - return helper.helperFunction.call(view, params, hash, options, env); - } - }); -enifed("ember-htmlbars/system/bootstrap", - ["ember-metal/core","ember-views/component_lookup","ember-views/system/jquery","ember-metal/error","ember-runtime/system/lazy_load","ember-template-compiler/system/compile","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - /*globals Handlebars */ - - /** - @module ember - @submodule ember-htmlbars - */ - - var Ember = __dependency1__["default"]; - var ComponentLookup = __dependency2__["default"]; - var jQuery = __dependency3__["default"]; - var EmberError = __dependency4__["default"]; - var onLoad = __dependency5__.onLoad; - var htmlbarsCompile = __dependency6__["default"]; - - /** - @module ember - @submodule ember-handlebars - */ - - /** - Find templates stored in the head tag as script tags and make them available - to `Ember.CoreView` in the global `Ember.TEMPLATES` object. This will be run - as as jQuery DOM-ready callback. - - Script tags with `text/x-handlebars` will be compiled - with Ember's Handlebars and are suitable for use as a view's template. - Those with type `text/x-raw-handlebars` will be compiled with regular - Handlebars and are suitable for use in views' computed properties. - - @private - @method bootstrap - @for Ember.Handlebars - @static - @param ctx - */ - function bootstrap(ctx) { - var selectors = 'script[type="text/x-handlebars"], script[type="text/x-raw-handlebars"]'; - - jQuery(selectors, ctx) - .each(function() { - // Get a reference to the script tag - var script = jQuery(this); - - var compile = (script.attr('type') === 'text/x-raw-handlebars') ? - jQuery.proxy(Handlebars.compile, Handlebars) : - htmlbarsCompile; - // Get the name of the script, used by Ember.View's templateName property. - // First look for data-template-name attribute, then fall back to its - // id if no name is found. - var templateName = script.attr('data-template-name') || script.attr('id') || 'application'; - var template = compile(script.html()); - - // Check if template of same name already exists - if (Ember.TEMPLATES[templateName] !== undefined) { - throw new EmberError('Template named "' + templateName + '" already exists.'); - } - - // For templates which have a name, we save them and then remove them from the DOM - Ember.TEMPLATES[templateName] = template; - - // Remove script tag from DOM - script.remove(); - }); - } - - function _bootstrap() { - bootstrap( jQuery(document) ); - } - - function registerComponentLookup(container) { - container.register('component-lookup:main', ComponentLookup); - } - - /* - We tie this to application.load to ensure that we've at least - attempted to bootstrap at the point that the application is loaded. - - We also tie this to document ready since we're guaranteed that all - the inline templates are present at this point. - - There's no harm to running this twice, since we remove the templates - from the DOM after processing. - */ - - onLoad('Ember.Application', function(Application) { - - - Application.initializer({ - name: 'domTemplates', - initialize: _bootstrap - }); - - Application.initializer({ - name: 'registerComponentLookup', - after: 'domTemplates', - initialize: registerComponentLookup - }); - - - }); - - __exports__["default"] = bootstrap; - }); -enifed("ember-htmlbars/system/helper", - ["exports"], - function(__exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - /** - @class Helper - @namespace Ember.HTMLBars - */ - function Helper(helper) { - this.helperFunction = helper; - - this.isHelper = true; - this.isHTMLBars = true; - } - - __exports__["default"] = Helper; - }); -enifed("ember-htmlbars/system/lookup-helper", - ["ember-metal/core","ember-metal/cache","ember-htmlbars/system/make-view-helper","ember-htmlbars/compat/helper","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var Ember = __dependency1__["default"]; - var Cache = __dependency2__["default"]; - var makeViewHelper = __dependency3__["default"]; - var HandlebarsCompatibleHelper = __dependency4__["default"]; - - var ISNT_HELPER_CACHE = new Cache(1000, function(key) { - return key.indexOf('-') === -1; - }); - __exports__.ISNT_HELPER_CACHE = ISNT_HELPER_CACHE; - /** - Used to lookup/resolve handlebars helpers. The lookup order is: - - * Look for a registered helper - * If a dash exists in the name: - * Look for a helper registed in the container - * Use Ember.ComponentLookup to find an Ember.Component that resolves - to the given name - - @private - @method resolveHelper - @param {Container} container - @param {String} name the name of the helper to lookup - @return {Handlebars Helper} - */ - __exports__["default"] = function lookupHelper(name, view, env) { - var helper = env.helpers[name]; - if (helper) { - return helper; - } - - var container = view.container; - - if (!container || ISNT_HELPER_CACHE.get(name)) { - return; - } - - var helperName = 'helper:' + name; - helper = container.lookup(helperName); - if (!helper) { - var componentLookup = container.lookup('component-lookup:main'); - Ember.assert("Could not find 'component-lookup:main' on the provided container," + - " which is necessary for performing component lookups", componentLookup); - - var Component = componentLookup.lookupFactory(name, container); - if (Component) { - helper = makeViewHelper(Component); - container.register(helperName, helper); - } - } - - if (helper && !helper.isHTMLBars) { - helper = new HandlebarsCompatibleHelper(helper); - container.unregister(helperName); - container.register(helperName, helper); - } - - return helper; - } - }); -enifed("ember-htmlbars/system/make-view-helper", - ["ember-metal/core","ember-htmlbars/system/helper","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var Helper = __dependency2__["default"]; - - /** - Returns a helper function that renders the provided ViewClass. - - Used internally by Ember.Handlebars.helper and other methods - involving helper/component registration. - - @private - @method makeViewHelper - @param {Function} ViewClass view class constructor - @since 1.2.0 - */ - __exports__["default"] = function makeViewHelper(ViewClass) { - function helperFunc(params, hash, options, env) { - Ember.assert("You can only pass attributes (such as name=value) not bare " + - "values to a helper for a View found in '" + ViewClass.toString() + "'", params.length === 0); - - return env.helpers.view.helperFunction.call(this, [ViewClass], hash, options, env); - } - - return new Helper(helperFunc); - } - }); -enifed("ember-htmlbars/system/make_bound_helper", - ["ember-metal/core","ember-htmlbars/system/helper","ember-metal/streams/stream","ember-metal/streams/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var Ember = __dependency1__["default"]; - // Ember.FEATURES, Ember.assert, Ember.Handlebars, Ember.lookup - var Helper = __dependency2__["default"]; - - var Stream = __dependency3__["default"]; - var readArray = __dependency4__.readArray; - var readHash = __dependency4__.readHash; - var subscribe = __dependency4__.subscribe; - var scanHash = __dependency4__.scanHash; - var scanArray = __dependency4__.scanArray; - - /** - Create a bound helper. Accepts a function that receives the ordered and hash parameters - from the template. If a bound property was provided in the template it will be resolved to its - value and any changes to the bound property cause the helper function to be re-ran with the updated - values. - - * `params` - An array of resolved ordered parameters. - * `hash` - An object containing the hash parameters. - - For example: - - * With an unqouted ordered parameter: - - ```javascript - {{x-capitalize foo}} - ``` - - Assuming `foo` was set to `"bar"`, the bound helper would receive `["bar"]` as its first argument, and - an empty hash as its second. - - * With a quoted ordered parameter: - - ```javascript - {{x-capitalize "foo"}} - ``` - - The bound helper would receive `["foo"]` as its first argument, and an empty hash as its second. - - * With an unquoted hash parameter: - - ```javascript - {{x-repeat "foo" count=repeatCount}} - ``` - - Assuming that `repeatCount` resolved to 2, the bound helper would receive `["foo"]` as its first argument, - and { count: 2 } as its second. - - @private - @method makeBoundHelper - @for Ember.HTMLBars - @param {Function} function - @since 1.10.0 - */ - __exports__["default"] = function makeBoundHelper(fn) { - function helperFunc(params, hash, options, env) { - var view = this; - var numParams = params.length; - var param, prop; - - Ember.assert("makeBoundHelper generated helpers do not support use with blocks", !options.template); - - function valueFn() { - return fn.call(view, readArray(params), readHash(hash), options, env); - } - - // If none of the hash parameters are bound, act as an unbound helper. - // This prevents views from being unnecessarily created - var hasStream = scanArray(params) || scanHash(hash); - - if (env.data.isUnbound || !hasStream) { - return valueFn(); - } else { - var lazyValue = new Stream(valueFn); - - for (var i = 0; i < numParams; i++) { - param = params[i]; - subscribe(param, lazyValue.notify, lazyValue); - } - - for (prop in hash) { - param = hash[prop]; - subscribe(param, lazyValue.notify, lazyValue); - } - - return lazyValue; - } - } - - return new Helper(helperFunc); - } - }); -enifed("ember-htmlbars/templates/component", - ["ember-template-compiler/system/template","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var template = __dependency1__["default"]; - var t = (function() { - return { - isHTMLBars: true, - blockParams: 0, - cachedFragment: null, - hasRendered: false, - build: function build(dom) { - var el0 = dom.createDocumentFragment(); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - return el0; - }, - render: function render(context, env, contextualElement) { - var dom = env.dom; - var hooks = env.hooks, content = hooks.content; - dom.detectNamespace(contextualElement); - var fragment; - if (env.useFragmentCache && dom.canClone) { - if (this.cachedFragment === null) { - fragment = this.build(dom); - if (this.hasRendered) { - this.cachedFragment = fragment; - } else { - this.hasRendered = true; - } - } - if (this.cachedFragment) { - fragment = dom.cloneNode(this.cachedFragment, true); - } - } else { - fragment = this.build(dom); - } - if (this.cachedFragment) { dom.repairClonedNode(fragment,[0,1]); } - var morph0 = dom.createMorphAt(fragment,0,1,contextualElement); - content(env, morph0, context, "yield"); - return fragment; - } - }; - }()); - __exports__["default"] = template(t); - }); -enifed("ember-htmlbars/templates/select-option", - ["ember-template-compiler/system/template","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var template = __dependency1__["default"]; - var t = (function() { - return { - isHTMLBars: true, - blockParams: 0, - cachedFragment: null, - hasRendered: false, - build: function build(dom) { - var el0 = dom.createDocumentFragment(); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - return el0; - }, - render: function render(context, env, contextualElement) { - var dom = env.dom; - var hooks = env.hooks, content = hooks.content; - dom.detectNamespace(contextualElement); - var fragment; - if (env.useFragmentCache && dom.canClone) { - if (this.cachedFragment === null) { - fragment = this.build(dom); - if (this.hasRendered) { - this.cachedFragment = fragment; - } else { - this.hasRendered = true; - } - } - if (this.cachedFragment) { - fragment = dom.cloneNode(this.cachedFragment, true); - } - } else { - fragment = this.build(dom); - } - if (this.cachedFragment) { dom.repairClonedNode(fragment,[0,1]); } - var morph0 = dom.createMorphAt(fragment,0,1,contextualElement); - content(env, morph0, context, "view.label"); - return fragment; - } - }; - }()); - __exports__["default"] = template(t); - }); -enifed("ember-htmlbars/templates/select", - ["ember-template-compiler/system/template","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var template = __dependency1__["default"]; - var t = (function() { - var child0 = (function() { - return { - isHTMLBars: true, - blockParams: 0, - cachedFragment: null, - hasRendered: false, - build: function build(dom) { - var el0 = dom.createElement("option"); - dom.setAttribute(el0,"value",""); - return el0; - }, - render: function render(context, env, contextualElement) { - var dom = env.dom; - var hooks = env.hooks, content = hooks.content; - dom.detectNamespace(contextualElement); - var fragment; - if (env.useFragmentCache && dom.canClone) { - if (this.cachedFragment === null) { - fragment = this.build(dom); - if (this.hasRendered) { - this.cachedFragment = fragment; - } else { - this.hasRendered = true; - } - } - if (this.cachedFragment) { - fragment = dom.cloneNode(this.cachedFragment, true); - } - } else { - fragment = this.build(dom); - } - var morph0 = dom.createMorphAt(fragment,-1,-1); - content(env, morph0, context, "view.prompt"); - return fragment; - } - }; - }()); - var child1 = (function() { - var child0 = (function() { - return { - isHTMLBars: true, - blockParams: 0, - cachedFragment: null, - hasRendered: false, - build: function build(dom) { - var el0 = dom.createDocumentFragment(); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - return el0; - }, - render: function render(context, env, contextualElement) { - var dom = env.dom; - var hooks = env.hooks, get = hooks.get, inline = hooks.inline; - dom.detectNamespace(contextualElement); - var fragment; - if (env.useFragmentCache && dom.canClone) { - if (this.cachedFragment === null) { - fragment = this.build(dom); - if (this.hasRendered) { - this.cachedFragment = fragment; - } else { - this.hasRendered = true; - } - } - if (this.cachedFragment) { - fragment = dom.cloneNode(this.cachedFragment, true); - } - } else { - fragment = this.build(dom); - } - if (this.cachedFragment) { dom.repairClonedNode(fragment,[0,1]); } - var morph0 = dom.createMorphAt(fragment,0,1,contextualElement); - inline(env, morph0, context, "view", [get(env, context, "view.groupView")], {"content": get(env, context, "group.content"), "label": get(env, context, "group.label")}); - return fragment; - } - }; - }()); - return { - isHTMLBars: true, - blockParams: 0, - cachedFragment: null, - hasRendered: false, - build: function build(dom) { - var el0 = dom.createDocumentFragment(); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - return el0; - }, - render: function render(context, env, contextualElement) { - var dom = env.dom; - var hooks = env.hooks, get = hooks.get, block = hooks.block; - dom.detectNamespace(contextualElement); - var fragment; - if (env.useFragmentCache && dom.canClone) { - if (this.cachedFragment === null) { - fragment = this.build(dom); - if (this.hasRendered) { - this.cachedFragment = fragment; - } else { - this.hasRendered = true; - } - } - if (this.cachedFragment) { - fragment = dom.cloneNode(this.cachedFragment, true); - } - } else { - fragment = this.build(dom); - } - if (this.cachedFragment) { dom.repairClonedNode(fragment,[0,1]); } - var morph0 = dom.createMorphAt(fragment,0,1,contextualElement); - block(env, morph0, context, "each", [get(env, context, "view.groupedContent")], {"keyword": "group"}, child0, null); - return fragment; - } - }; - }()); - var child2 = (function() { - var child0 = (function() { - return { - isHTMLBars: true, - blockParams: 0, - cachedFragment: null, - hasRendered: false, - build: function build(dom) { - var el0 = dom.createDocumentFragment(); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - return el0; - }, - render: function render(context, env, contextualElement) { - var dom = env.dom; - var hooks = env.hooks, get = hooks.get, inline = hooks.inline; - dom.detectNamespace(contextualElement); - var fragment; - if (env.useFragmentCache && dom.canClone) { - if (this.cachedFragment === null) { - fragment = this.build(dom); - if (this.hasRendered) { - this.cachedFragment = fragment; - } else { - this.hasRendered = true; - } - } - if (this.cachedFragment) { - fragment = dom.cloneNode(this.cachedFragment, true); - } - } else { - fragment = this.build(dom); - } - if (this.cachedFragment) { dom.repairClonedNode(fragment,[0,1]); } - var morph0 = dom.createMorphAt(fragment,0,1,contextualElement); - inline(env, morph0, context, "view", [get(env, context, "view.optionView")], {"content": get(env, context, "item")}); - return fragment; - } - }; - }()); - return { - isHTMLBars: true, - blockParams: 0, - cachedFragment: null, - hasRendered: false, - build: function build(dom) { - var el0 = dom.createDocumentFragment(); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - return el0; - }, - render: function render(context, env, contextualElement) { - var dom = env.dom; - var hooks = env.hooks, get = hooks.get, block = hooks.block; - dom.detectNamespace(contextualElement); - var fragment; - if (env.useFragmentCache && dom.canClone) { - if (this.cachedFragment === null) { - fragment = this.build(dom); - if (this.hasRendered) { - this.cachedFragment = fragment; - } else { - this.hasRendered = true; - } - } - if (this.cachedFragment) { - fragment = dom.cloneNode(this.cachedFragment, true); - } - } else { - fragment = this.build(dom); - } - if (this.cachedFragment) { dom.repairClonedNode(fragment,[0,1]); } - var morph0 = dom.createMorphAt(fragment,0,1,contextualElement); - block(env, morph0, context, "each", [get(env, context, "view.content")], {"keyword": "item"}, child0, null); - return fragment; - } - }; - }()); - return { - isHTMLBars: true, - blockParams: 0, - cachedFragment: null, - hasRendered: false, - build: function build(dom) { - var el0 = dom.createDocumentFragment(); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - var el1 = dom.createTextNode(""); - dom.appendChild(el0, el1); - var el1 = dom.createTextNode("\n"); - dom.appendChild(el0, el1); - return el0; - }, - render: function render(context, env, contextualElement) { - var dom = env.dom; - var hooks = env.hooks, get = hooks.get, block = hooks.block; - dom.detectNamespace(contextualElement); - var fragment; - if (env.useFragmentCache && dom.canClone) { - if (this.cachedFragment === null) { - fragment = this.build(dom); - if (this.hasRendered) { - this.cachedFragment = fragment; - } else { - this.hasRendered = true; - } - } - if (this.cachedFragment) { - fragment = dom.cloneNode(this.cachedFragment, true); - } - } else { - fragment = this.build(dom); - } - if (this.cachedFragment) { dom.repairClonedNode(fragment,[0,1]); } - var morph0 = dom.createMorphAt(fragment,0,1,contextualElement); - var morph1 = dom.createMorphAt(fragment,1,2,contextualElement); - block(env, morph0, context, "if", [get(env, context, "view.prompt")], {}, child0, null); - block(env, morph1, context, "if", [get(env, context, "view.optionGroupPath")], {}, child1, child2); - return fragment; - } - }; - }()); - __exports__["default"] = template(t); - }); -enifed("ember-htmlbars/utils/string", - ["htmlbars-util","ember-runtime/system/string","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - // required so we can extend this object. - var SafeString = __dependency1__.SafeString; - var escapeExpression = __dependency1__.escapeExpression; - var EmberStringUtils = __dependency2__["default"]; - - /** - Mark a string as safe for unescaped output with Handlebars. If you - return HTML from a Handlebars helper, use this function to - ensure Handlebars does not escape the HTML. - - ```javascript - Ember.String.htmlSafe('
    someString
    ') - ``` - - @method htmlSafe - @for Ember.String - @static - @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars - */ - function htmlSafe(str) { - if (str === null || str === undefined) { - return ""; - } - - if (typeof str !== 'string') { - str = ''+str; - } - return new SafeString(str); - } - - EmberStringUtils.htmlSafe = htmlSafe; - if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { - - /** - Mark a string as being safe for unescaped output with Handlebars. - - ```javascript - '
    someString
    '.htmlSafe() - ``` - - See [Ember.String.htmlSafe](/api/classes/Ember.String.html#method_htmlSafe). - - @method htmlSafe - @for String - @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars - */ - String.prototype.htmlSafe = function() { - return htmlSafe(this); - }; - } - - __exports__.SafeString = SafeString; - __exports__.htmlSafe = htmlSafe; - __exports__.escapeExpression = escapeExpression; - }); -enifed("ember-metal-views", - ["ember-metal-views/renderer","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Renderer = __dependency1__["default"]; - __exports__.Renderer = Renderer; - }); -enifed("ember-metal-views/renderer", - ["morph","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var DOMHelper = __dependency1__.DOMHelper; - - function Renderer() { - this._uuid = 0; - this._views = new Array(2000); - this._queue = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; - this._parents = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; - this._elements = new Array(17); - this._inserts = {}; - this._dom = new DOMHelper(); - } - - function Renderer_renderTree(_view, _parentView, _insertAt) { - var views = this._views; - views[0] = _view; - var insertAt = _insertAt === undefined ? -1 : _insertAt; - var index = 0; - var total = 1; - var levelBase = _parentView ? _parentView._level+1 : 0; - - var root = _parentView == null ? _view : _parentView._root; - - // if root view has a _morph assigned - var willInsert = !!root._morph; - - var queue = this._queue; - queue[0] = 0; - var length = 1; - - var parentIndex = -1; - var parents = this._parents; - var parent = _parentView || null; - var elements = this._elements; - var element = null; - var contextualElement = null; - var level = 0; - - var view = _view; - var children, i, child; - while (length) { - elements[level] = element; - if (!view._morph) { - // ensure props we add are in same order - view._morph = null; - } - view._root = root; - this.uuid(view); - view._level = levelBase + level; - if (view._elementCreated) { - this.remove(view, false, true); - } - - this.willCreateElement(view); - - contextualElement = view._morph && view._morph.contextualElement; - if (!contextualElement && parent && parent._childViewsMorph) { - contextualElement = parent._childViewsMorph.contextualElement; - } - if (!contextualElement && view._didCreateElementWithoutMorph) { - // This code path is only used by createElement and rerender when createElement - // was previously called on a view. - contextualElement = document.body; - } - element = this.createElement(view, contextualElement); - - parents[level++] = parentIndex; - parentIndex = index; - parent = view; - - // enqueue for end - queue[length++] = index; - // enqueue children - children = this.childViews(view); - if (children) { - for (i=children.length-1;i>=0;i--) { - child = children[i]; - index = total++; - views[index] = child; - queue[length++] = index; - view = child; - } - } - - index = queue[--length]; - view = views[index]; - - while (parentIndex === index) { - level--; - view._elementCreated = true; - this.didCreateElement(view); - if (willInsert) { - this.willInsertElement(view); - } - - if (level === 0) { - length--; - break; - } - - parentIndex = parents[level]; - parent = parentIndex === -1 ? _parentView : views[parentIndex]; - this.insertElement(view, parent, element, -1); - index = queue[--length]; - view = views[index]; - element = elements[level]; - elements[level] = null; - } - } - - this.insertElement(view, _parentView, element, insertAt); - - for (i=total-1; i>=0; i--) { - if (willInsert) { - views[i]._elementInserted = true; - this.didInsertElement(views[i]); - } - views[i] = null; - } - - return element; - } - - Renderer.prototype.uuid = function Renderer_uuid(view) { - if (view._uuid === undefined) { - view._uuid = ++this._uuid; - view._renderer = this; - } // else assert(view._renderer === this) - return view._uuid; - }; - - Renderer.prototype.scheduleInsert = - function Renderer_scheduleInsert(view, morph) { - if (view._morph || view._elementCreated) { - throw new Error("You cannot insert a View that has already been rendered"); - } - Ember.assert("You cannot insert a View without a morph", morph); - view._morph = morph; - var viewId = this.uuid(view); - this._inserts[viewId] = this.scheduleRender(this, function scheduledRenderTree() { - this._inserts[viewId] = null; - this.renderTree(view); - }); - }; - - Renderer.prototype.appendTo = - function Renderer_appendTo(view, target) { - var morph = this._dom.appendMorph(target); - this.scheduleInsert(view, morph); - }; - - Renderer.prototype.replaceIn = - function Renderer_replaceIn(view, target) { - var morph = this._dom.createMorph(target, null, null); - this.scheduleInsert(view, morph); - }; - - function Renderer_remove(_view, shouldDestroy, reset) { - var viewId = this.uuid(_view); - - if (this._inserts[viewId]) { - this.cancelRender(this._inserts[viewId]); - this._inserts[viewId] = undefined; - } - - if (!_view._elementCreated) { - return; - } - - var removeQueue = []; - var destroyQueue = []; - var morph = _view._morph; - var idx, len, view, queue, childViews, i, l; - - removeQueue.push(_view); - - for (idx=0; idx -1; - }; - - var defineNativeShim = function(nativeFunc, shim) { - if (isNativeFunc(nativeFunc)) { - return nativeFunc; - } - return shim; - }; - - // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/map - var map = defineNativeShim(ArrayPrototype.map, function(fun /*, thisp */) { - //"use strict"; - - if (this === void 0 || this === null || typeof fun !== "function") { - throw new TypeError(); - } - - var t = Object(this); - var len = t.length >>> 0; - var res = new Array(len); - var thisp = arguments[1]; - - for (var i = 0; i < len; i++) { - if (i in t) { - res[i] = fun.call(thisp, t[i], i, t); - } - } - - return res; - }); - - // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/foreach - var forEach = defineNativeShim(ArrayPrototype.forEach, function(fun /*, thisp */) { - //"use strict"; - - if (this === void 0 || this === null || typeof fun !== "function") { - throw new TypeError(); - } - - var t = Object(this); - var len = t.length >>> 0; - var thisp = arguments[1]; - - for (var i = 0; i < len; i++) { - if (i in t) { - fun.call(thisp, t[i], i, t); - } - } - }); - - var indexOf = defineNativeShim(ArrayPrototype.indexOf, function (obj, fromIndex) { - if (fromIndex === null || fromIndex === undefined) { - fromIndex = 0; - } - else if (fromIndex < 0) { - fromIndex = Math.max(0, this.length + fromIndex); - } - - for (var i = fromIndex, j = this.length; i < j; i++) { - if (this[i] === obj) { - return i; - } - } - return -1; - }); - - var lastIndexOf = defineNativeShim(ArrayPrototype.lastIndexOf, function(obj, fromIndex) { - var len = this.length; - var idx; - - if (fromIndex === undefined) fromIndex = len-1; - else fromIndex = (fromIndex < 0) ? Math.ceil(fromIndex) : Math.floor(fromIndex); - if (fromIndex < 0) fromIndex += len; - - for(idx = fromIndex;idx>=0;idx--) { - if (this[idx] === obj) return idx ; - } - return -1; - }); - - var filter = defineNativeShim(ArrayPrototype.filter, function (fn, context) { - var i, value; - var result = []; - var length = this.length; - - for (i = 0; i < length; i++) { - if (this.hasOwnProperty(i)) { - value = this[i]; - if (fn.call(context, value, i, this)) { - result.push(value); - } - } - } - return result; - }); - - if (Ember.SHIM_ES5) { - ArrayPrototype.map = ArrayPrototype.map || map; - ArrayPrototype.forEach = ArrayPrototype.forEach || forEach; - ArrayPrototype.filter = ArrayPrototype.filter || filter; - ArrayPrototype.indexOf = ArrayPrototype.indexOf || indexOf; - ArrayPrototype.lastIndexOf = ArrayPrototype.lastIndexOf || lastIndexOf; - } - - /** - Array polyfills to support ES5 features in older browsers. - - @namespace Ember - @property ArrayPolyfills - */ - __exports__.map = map; - __exports__.forEach = forEach; - __exports__.filter = filter; - __exports__.indexOf = indexOf; - __exports__.lastIndexOf = lastIndexOf; - }); -enifed("ember-metal/binding", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/run_loop","ember-metal/path_cache","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.Logger, Ember.LOG_BINDINGS, assert - var get = __dependency2__.get; - var trySet = __dependency3__.trySet; - var guidFor = __dependency4__.guidFor; - var addObserver = __dependency5__.addObserver; - var removeObserver = __dependency5__.removeObserver; - var _suspendObserver = __dependency5__._suspendObserver; - var run = __dependency6__["default"]; - var isGlobalPath = __dependency7__.isGlobal; - - - // ES6TODO: where is Ember.lookup defined? - /** - @module ember-metal - */ - - // .......................................................... - // CONSTANTS - // - - /** - Debug parameter you can turn on. This will log all bindings that fire to - the console. This should be disabled in production code. Note that you - can also enable this from the console or temporarily. - - @property LOG_BINDINGS - @for Ember - @type Boolean - @default false - */ - Ember.LOG_BINDINGS = false || !!Ember.ENV.LOG_BINDINGS; - - /** - Returns true if the provided path is global (e.g., `MyApp.fooController.bar`) - instead of local (`foo.bar.baz`). - - @method isGlobalPath - @for Ember - @private - @param {String} path - @return Boolean - */ - - function getWithGlobals(obj, path) { - return get(isGlobalPath(path) ? Ember.lookup : obj, path); - } - - // .......................................................... - // BINDING - // - - function Binding(toPath, fromPath) { - this._direction = undefined; - this._from = fromPath; - this._to = toPath; - this._readyToSync = undefined; - this._oneWay = undefined; - } - - /** - @class Binding - @namespace Ember - */ - - Binding.prototype = { - /** - This copies the Binding so it can be connected to another object. - - @method copy - @return {Ember.Binding} `this` - */ - copy: function () { - var copy = new Binding(this._to, this._from); - if (this._oneWay) { copy._oneWay = true; } - return copy; - }, - - // .......................................................... - // CONFIG - // - - /** - This will set `from` property path to the specified value. It will not - attempt to resolve this property path to an actual object until you - connect the binding. - - The binding will search for the property path starting at the root object - you pass when you `connect()` the binding. It follows the same rules as - `get()` - see that method for more information. - - @method from - @param {String} path the property path to connect to - @return {Ember.Binding} `this` - */ - from: function(path) { - this._from = path; - return this; - }, - - /** - This will set the `to` property path to the specified value. It will not - attempt to resolve this property path to an actual object until you - connect the binding. - - The binding will search for the property path starting at the root object - you pass when you `connect()` the binding. It follows the same rules as - `get()` - see that method for more information. - - @method to - @param {String|Tuple} path A property path or tuple - @return {Ember.Binding} `this` - */ - to: function(path) { - this._to = path; - return this; - }, - - /** - Configures the binding as one way. A one-way binding will relay changes - on the `from` side to the `to` side, but not the other way around. This - means that if you change the `to` side directly, the `from` side may have - a different value. - - @method oneWay - @return {Ember.Binding} `this` - */ - oneWay: function() { - this._oneWay = true; - return this; - }, - - /** - @method toString - @return {String} string representation of binding - */ - toString: function() { - var oneWay = this._oneWay ? '[oneWay]' : ''; - return "Ember.Binding<" + guidFor(this) + ">(" + this._from + " -> " + this._to + ")" + oneWay; - }, - - // .......................................................... - // CONNECT AND SYNC - // - - /** - Attempts to connect this binding instance so that it can receive and relay - changes. This method will raise an exception if you have not set the - from/to properties yet. - - @method connect - @param {Object} obj The root object for this binding. - @return {Ember.Binding} `this` - */ - connect: function(obj) { - Ember.assert('Must pass a valid object to Ember.Binding.connect()', !!obj); - - var fromPath = this._from; - var toPath = this._to; - trySet(obj, toPath, getWithGlobals(obj, fromPath)); - - // add an observer on the object to be notified when the binding should be updated - addObserver(obj, fromPath, this, this.fromDidChange); - - // if the binding is a two-way binding, also set up an observer on the target - if (!this._oneWay) { - addObserver(obj, toPath, this, this.toDidChange); - } - - this._readyToSync = true; - - return this; - }, - - /** - Disconnects the binding instance. Changes will no longer be relayed. You - will not usually need to call this method. - - @method disconnect - @param {Object} obj The root object you passed when connecting the binding. - @return {Ember.Binding} `this` - */ - disconnect: function(obj) { - Ember.assert('Must pass a valid object to Ember.Binding.disconnect()', !!obj); - - var twoWay = !this._oneWay; - - // remove an observer on the object so we're no longer notified of - // changes that should update bindings. - removeObserver(obj, this._from, this, this.fromDidChange); - - // if the binding is two-way, remove the observer from the target as well - if (twoWay) { - removeObserver(obj, this._to, this, this.toDidChange); - } - - this._readyToSync = false; // disable scheduled syncs... - return this; - }, - - // .......................................................... - // PRIVATE - // - - /* called when the from side changes */ - fromDidChange: function(target) { - this._scheduleSync(target, 'fwd'); - }, - - /* called when the to side changes */ - toDidChange: function(target) { - this._scheduleSync(target, 'back'); - }, - - _scheduleSync: function(obj, dir) { - var existingDir = this._direction; - - // if we haven't scheduled the binding yet, schedule it - if (existingDir === undefined) { - run.schedule('sync', this, this._sync, obj); - this._direction = dir; - } - - // If both a 'back' and 'fwd' sync have been scheduled on the same object, - // default to a 'fwd' sync so that it remains deterministic. - if (existingDir === 'back' && dir === 'fwd') { - this._direction = 'fwd'; - } - }, - - _sync: function(obj) { - var log = Ember.LOG_BINDINGS; - - // don't synchronize destroyed objects or disconnected bindings - if (obj.isDestroyed || !this._readyToSync) { return; } - - // get the direction of the binding for the object we are - // synchronizing from - var direction = this._direction; - - var fromPath = this._from; - var toPath = this._to; - - this._direction = undefined; - - // if we're synchronizing from the remote object... - if (direction === 'fwd') { - var fromValue = getWithGlobals(obj, this._from); - if (log) { - Ember.Logger.log(' ', this.toString(), '->', fromValue, obj); - } - if (this._oneWay) { - trySet(obj, toPath, fromValue); - } else { - _suspendObserver(obj, toPath, this, this.toDidChange, function () { - trySet(obj, toPath, fromValue); - }); - } - // if we're synchronizing *to* the remote object - } else if (direction === 'back') { - var toValue = get(obj, this._to); - if (log) { - Ember.Logger.log(' ', this.toString(), '<-', toValue, obj); - } - _suspendObserver(obj, fromPath, this, this.fromDidChange, function () { - trySet(isGlobalPath(fromPath) ? Ember.lookup : obj, fromPath, toValue); - }); - } - } - - }; - - function mixinProperties(to, from) { - for (var key in from) { - if (from.hasOwnProperty(key)) { - to[key] = from[key]; - } - } - } - - mixinProperties(Binding, { - - /* - See `Ember.Binding.from`. - - @method from - @static - */ - from: function(from) { - var C = this; - return new C(undefined, from); - }, - - /* - See `Ember.Binding.to`. - - @method to - @static - */ - to: function(to) { - var C = this; - return new C(to, undefined); - }, - - /** - Creates a new Binding instance and makes it apply in a single direction. - A one-way binding will relay changes on the `from` side object (supplied - as the `from` argument) the `to` side, but not the other way around. - This means that if you change the "to" side directly, the "from" side may have - a different value. - - See `Binding.oneWay`. - - @method oneWay - @param {String} from from path. - @param {Boolean} [flag] (Optional) passing nothing here will make the - binding `oneWay`. You can instead pass `false` to disable `oneWay`, making the - binding two way again. - @return {Ember.Binding} `this` - */ - oneWay: function(from, flag) { - var C = this; - return new C(undefined, from).oneWay(flag); - } - - }); - /** - An `Ember.Binding` connects the properties of two objects so that whenever - the value of one property changes, the other property will be changed also. - - ## Automatic Creation of Bindings with `/^*Binding/`-named Properties - - You do not usually create Binding objects directly but instead describe - bindings in your class or object definition using automatic binding - detection. - - Properties ending in a `Binding` suffix will be converted to `Ember.Binding` - instances. The value of this property should be a string representing a path - to another object or a custom binding instance created using Binding helpers - (see "One Way Bindings"): - - ``` - valueBinding: "MyApp.someController.title" - ``` - - This will create a binding from `MyApp.someController.title` to the `value` - property of your object instance automatically. Now the two values will be - kept in sync. - - ## One Way Bindings - - One especially useful binding customization you can use is the `oneWay()` - helper. This helper tells Ember that you are only interested in - receiving changes on the object you are binding from. For example, if you - are binding to a preference and you want to be notified if the preference - has changed, but your object will not be changing the preference itself, you - could do: - - ``` - bigTitlesBinding: Ember.Binding.oneWay("MyApp.preferencesController.bigTitles") - ``` - - This way if the value of `MyApp.preferencesController.bigTitles` changes the - `bigTitles` property of your object will change also. However, if you - change the value of your `bigTitles` property, it will not update the - `preferencesController`. - - One way bindings are almost twice as fast to setup and twice as fast to - execute because the binding only has to worry about changes to one side. - - You should consider using one way bindings anytime you have an object that - may be created frequently and you do not intend to change a property; only - to monitor it for changes (such as in the example above). - - ## Adding Bindings Manually - - All of the examples above show you how to configure a custom binding, but the - result of these customizations will be a binding template, not a fully active - Binding instance. The binding will actually become active only when you - instantiate the object the binding belongs to. It is useful however, to - understand what actually happens when the binding is activated. - - For a binding to function it must have at least a `from` property and a `to` - property. The `from` property path points to the object/key that you want to - bind from while the `to` path points to the object/key you want to bind to. - - When you define a custom binding, you are usually describing the property - you want to bind from (such as `MyApp.someController.value` in the examples - above). When your object is created, it will automatically assign the value - you want to bind `to` based on the name of your binding key. In the - examples above, during init, Ember objects will effectively call - something like this on your binding: - - ```javascript - binding = Ember.Binding.from("valueBinding").to("value"); - ``` - - This creates a new binding instance based on the template you provide, and - sets the to path to the `value` property of the new object. Now that the - binding is fully configured with a `from` and a `to`, it simply needs to be - connected to become active. This is done through the `connect()` method: - - ```javascript - binding.connect(this); - ``` - - Note that when you connect a binding you pass the object you want it to be - connected to. This object will be used as the root for both the from and - to side of the binding when inspecting relative paths. This allows the - binding to be automatically inherited by subclassed objects as well. - - This also allows you to bind between objects using the paths you declare in - `from` and `to`: - - ```javascript - // Example 1 - binding = Ember.Binding.from("App.someObject.value").to("value"); - binding.connect(this); - - // Example 2 - binding = Ember.Binding.from("parentView.value").to("App.someObject.value"); - binding.connect(this); - ``` - - Now that the binding is connected, it will observe both the from and to side - and relay changes. - - If you ever needed to do so (you almost never will, but it is useful to - understand this anyway), you could manually create an active binding by - using the `Ember.bind()` helper method. (This is the same method used by - to setup your bindings on objects): - - ```javascript - Ember.bind(MyApp.anotherObject, "value", "MyApp.someController.value"); - ``` - - Both of these code fragments have the same effect as doing the most friendly - form of binding creation like so: - - ```javascript - MyApp.anotherObject = Ember.Object.create({ - valueBinding: "MyApp.someController.value", - - // OTHER CODE FOR THIS OBJECT... - }); - ``` - - Ember's built in binding creation method makes it easy to automatically - create bindings for you. You should always use the highest-level APIs - available, even if you understand how it works underneath. - - @class Binding - @namespace Ember - @since Ember 0.9 - */ - // Ember.Binding = Binding; ES6TODO: where to put this? - - - /** - Global helper method to create a new binding. Just pass the root object - along with a `to` and `from` path to create and connect the binding. - - @method bind - @for Ember - @param {Object} obj The root object of the transform. - @param {String} to The path to the 'to' side of the binding. - Must be relative to obj. - @param {String} from The path to the 'from' side of the binding. - Must be relative to obj or a global path. - @return {Ember.Binding} binding instance - */ - function bind(obj, to, from) { - return new Binding(to, from).connect(obj); - } - - __exports__.bind = bind;/** - @method oneWay - @for Ember - @param {Object} obj The root object of the transform. - @param {String} to The path to the 'to' side of the binding. - Must be relative to obj. - @param {String} from The path to the 'from' side of the binding. - Must be relative to obj or a global path. - @return {Ember.Binding} binding instance - */ - function oneWay(obj, to, from) { - return new Binding(to, from).oneWay().connect(obj); - } - - __exports__.oneWay = oneWay;__exports__.Binding = Binding; - __exports__.isGlobalPath = isGlobalPath; - }); -enifed("ember-metal/cache", - ["ember-metal/dictionary","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var dictionary = __dependency1__["default"]; - __exports__["default"] = Cache; - - function Cache(limit, func) { - this.store = dictionary(null); - this.size = 0; - this.misses = 0; - this.hits = 0; - this.limit = limit; - this.func = func; - } - - var UNDEFINED = function() { }; - - Cache.prototype = { - set: function(key, value) { - if (this.limit > this.size) { - this.size ++; - if (value === undefined) { - this.store[key] = UNDEFINED; - } else { - this.store[key] = value; - } - } - - return value; - }, - - get: function(key) { - var value = this.store[key]; - - if (value === undefined) { - this.misses ++; - value = this.set(key, this.func(key)); - } else if (value === UNDEFINED) { - this.hits ++; - value = undefined; - } else { - this.hits ++; - // nothing to translate - } - - return value; - }, - - purge: function() { - this.store = dictionary(null); - this.size = 0; - this.hits = 0; - this.misses = 0; - } - }; - }); -enifed("ember-metal/chains", - ["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/array","ember-metal/watch_key","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // warn, assert, etc; - var get = __dependency2__.get; - var normalizeTuple = __dependency2__.normalizeTuple; - var metaFor = __dependency3__.meta; - var forEach = __dependency4__.forEach; - var watchKey = __dependency5__.watchKey; - var unwatchKey = __dependency5__.unwatchKey; - - var warn = Ember.warn; - var FIRST_KEY = /^([^\.]+)/; - - function firstKey(path) { - return path.match(FIRST_KEY)[0]; - } - - var pendingQueue = []; - - // attempts to add the pendingQueue chains again. If some of them end up - // back in the queue and reschedule is true, schedules a timeout to try - // again. - function flushPendingChains() { - if (pendingQueue.length === 0) { return; } // nothing to do - - var queue = pendingQueue; - pendingQueue = []; - - forEach.call(queue, function(q) { - q[0].add(q[1]); - }); - - warn('Watching an undefined global, Ember expects watched globals to be' + - ' setup by the time the run loop is flushed, check for typos', pendingQueue.length === 0); - } - - __exports__.flushPendingChains = flushPendingChains;function addChainWatcher(obj, keyName, node) { - if (!obj || ('object' !== typeof obj)) { return; } // nothing to do - - var m = metaFor(obj); - var nodes = m.chainWatchers; - - if (!m.hasOwnProperty('chainWatchers')) { - nodes = m.chainWatchers = {}; - } - - if (!nodes[keyName]) { - nodes[keyName] = []; - } - nodes[keyName].push(node); - watchKey(obj, keyName, m); - } - - function removeChainWatcher(obj, keyName, node) { - if (!obj || 'object' !== typeof obj) { return; } // nothing to do - - var m = obj['__ember_meta__']; - if (m && !m.hasOwnProperty('chainWatchers')) { return; } // nothing to do - - var nodes = m && m.chainWatchers; - - if (nodes && nodes[keyName]) { - nodes = nodes[keyName]; - for (var i = 0, l = nodes.length; i < l; i++) { - if (nodes[i] === node) { - nodes.splice(i, 1); - break; - } - } - } - unwatchKey(obj, keyName, m); - } - - // A ChainNode watches a single key on an object. If you provide a starting - // value for the key then the node won't actually watch it. For a root node - // pass null for parent and key and object for value. - function ChainNode(parent, key, value) { - this._parent = parent; - this._key = key; - - // _watching is true when calling get(this._parent, this._key) will - // return the value of this node. - // - // It is false for the root of a chain (because we have no parent) - // and for global paths (because the parent node is the object with - // the observer on it) - this._watching = value===undefined; - - this._value = value; - this._paths = {}; - if (this._watching) { - this._object = parent.value(); - if (this._object) { - addChainWatcher(this._object, this._key, this); - } - } - - // Special-case: the EachProxy relies on immediate evaluation to - // establish its observers. - // - // TODO: Replace this with an efficient callback that the EachProxy - // can implement. - if (this._parent && this._parent._key === '@each') { - this.value(); - } - } - - var ChainNodePrototype = ChainNode.prototype; - - function lazyGet(obj, key) { - if (!obj) return undefined; - - var meta = obj['__ember_meta__']; - // check if object meant only to be a prototype - if (meta && meta.proto === obj) { - return undefined; - } - - if (key === "@each") { - return get(obj, key); - } - - // if a CP only return cached value - var desc = meta && meta.descs[key]; - if (desc && desc._cacheable) { - if (key in meta.cache) { - return meta.cache[key]; - } else { - return undefined; - } - } - - return get(obj, key); - } - - ChainNodePrototype.value = function() { - if (this._value === undefined && this._watching) { - var obj = this._parent.value(); - this._value = lazyGet(obj, this._key); - } - return this._value; - }; - - ChainNodePrototype.destroy = function() { - if (this._watching) { - var obj = this._object; - if (obj) { - removeChainWatcher(obj, this._key, this); - } - this._watching = false; // so future calls do nothing - } - }; - - // copies a top level object only - ChainNodePrototype.copy = function(obj) { - var ret = new ChainNode(null, null, obj); - var paths = this._paths; - var path; - - for (path in paths) { - // this check will also catch non-number vals. - if (paths[path] <= 0) { - continue; - } - ret.add(path); - } - return ret; - }; - - // called on the root node of a chain to setup watchers on the specified - // path. - ChainNodePrototype.add = function(path) { - var obj, tuple, key, src, paths; - - paths = this._paths; - paths[path] = (paths[path] || 0) + 1; - - obj = this.value(); - tuple = normalizeTuple(obj, path); - - // the path was a local path - if (tuple[0] && tuple[0] === obj) { - path = tuple[1]; - key = firstKey(path); - path = path.slice(key.length+1); - - // global path, but object does not exist yet. - // put into a queue and try to connect later. - } else if (!tuple[0]) { - pendingQueue.push([this, path]); - tuple.length = 0; - return; - - // global path, and object already exists - } else { - src = tuple[0]; - key = path.slice(0, 0-(tuple[1].length+1)); - path = tuple[1]; - } - - tuple.length = 0; - this.chain(key, path, src); - }; - - // called on the root node of a chain to teardown watcher on the specified - // path - ChainNodePrototype.remove = function(path) { - var obj, tuple, key, src, paths; - - paths = this._paths; - if (paths[path] > 0) { - paths[path]--; - } - - obj = this.value(); - tuple = normalizeTuple(obj, path); - if (tuple[0] === obj) { - path = tuple[1]; - key = firstKey(path); - path = path.slice(key.length+1); - } else { - src = tuple[0]; - key = path.slice(0, 0-(tuple[1].length+1)); - path = tuple[1]; - } - - tuple.length = 0; - this.unchain(key, path); - }; - - ChainNodePrototype.count = 0; - - ChainNodePrototype.chain = function(key, path, src) { - var chains = this._chains; - var node; - if (!chains) { - chains = this._chains = {}; - } - - node = chains[key]; - if (!node) { - node = chains[key] = new ChainNode(this, key, src); - } - node.count++; // count chains... - - // chain rest of path if there is one - if (path) { - key = firstKey(path); - path = path.slice(key.length+1); - node.chain(key, path); // NOTE: no src means it will observe changes... - } - }; - - ChainNodePrototype.unchain = function(key, path) { - var chains = this._chains; - var node = chains[key]; - - // unchain rest of path first... - if (path && path.length > 1) { - var nextKey = firstKey(path); - var nextPath = path.slice(nextKey.length + 1); - node.unchain(nextKey, nextPath); - } - - // delete node if needed. - node.count--; - if (node.count<=0) { - delete chains[node._key]; - node.destroy(); - } - - }; - - ChainNodePrototype.willChange = function(events) { - var chains = this._chains; - if (chains) { - for(var key in chains) { - if (!chains.hasOwnProperty(key)) { - continue; - } - chains[key].willChange(events); - } - } - - if (this._parent) { - this._parent.chainWillChange(this, this._key, 1, events); - } - }; - - ChainNodePrototype.chainWillChange = function(chain, path, depth, events) { - if (this._key) { - path = this._key + '.' + path; - } - - if (this._parent) { - this._parent.chainWillChange(this, path, depth+1, events); - } else { - if (depth > 1) { - events.push(this.value(), path); - } - path = 'this.' + path; - if (this._paths[path] > 0) { - events.push(this.value(), path); - } - } - }; - - ChainNodePrototype.chainDidChange = function(chain, path, depth, events) { - if (this._key) { - path = this._key + '.' + path; - } - - if (this._parent) { - this._parent.chainDidChange(this, path, depth+1, events); - } else { - if (depth > 1) { - events.push(this.value(), path); - } - path = 'this.' + path; - if (this._paths[path] > 0) { - events.push(this.value(), path); - } - } - }; - - ChainNodePrototype.didChange = function(events) { - // invalidate my own value first. - if (this._watching) { - var obj = this._parent.value(); - if (obj !== this._object) { - removeChainWatcher(this._object, this._key, this); - this._object = obj; - addChainWatcher(obj, this._key, this); - } - this._value = undefined; - - // Special-case: the EachProxy relies on immediate evaluation to - // establish its observers. - if (this._parent && this._parent._key === '@each') { - this.value(); - } - } - - // then notify chains... - var chains = this._chains; - if (chains) { - for(var key in chains) { - if (!chains.hasOwnProperty(key)) { continue; } - chains[key].didChange(events); - } - } - - // if no events are passed in then we only care about the above wiring update - if (events === null) { - return; - } - - // and finally tell parent about my path changing... - if (this._parent) { - this._parent.chainDidChange(this, this._key, 1, events); - } - }; - - function finishChains(obj) { - // We only create meta if we really have to - var m = obj['__ember_meta__']; - var chains, chainWatchers, chainNodes; - - if (m) { - // finish any current chains node watchers that reference obj - chainWatchers = m.chainWatchers; - if (chainWatchers) { - for(var key in chainWatchers) { - if (!chainWatchers.hasOwnProperty(key)) { - continue; - } - - chainNodes = chainWatchers[key]; - if (chainNodes) { - for (var i=0,l=chainNodes.length;i 1) { - args = a_slice.call(arguments); - func = args.pop(); - } - - if (typeof func !== "function") { - throw new EmberError("Computed Property declared without a property function"); - } - - var cp = new ComputedProperty(func); - - if (args) { - cp.property.apply(cp, args); - } - - return cp; - } - - /** - Returns the cached value for a property, if one exists. - This can be useful for peeking at the value of a computed - property that is generated lazily, without accidentally causing - it to be created. - - @method cacheFor - @for Ember - @param {Object} obj the object whose property you want to check - @param {String} key the name of the property whose cached value you want - to return - @return {Object} the cached value - */ - function cacheFor(obj, key) { - var meta = obj['__ember_meta__']; - var cache = meta && meta.cache; - var ret = cache && cache[key]; - - if (ret === UNDEFINED) { - return undefined; - } - return ret; - } - - cacheFor.set = function(cache, key, value) { - if (value === undefined) { - cache[key] = UNDEFINED; - } else { - cache[key] = value; - } - }; - - cacheFor.get = function(cache, key) { - var ret = cache[key]; - if (ret === UNDEFINED) { - return undefined; - } - return ret; - }; - - cacheFor.remove = function(cache, key) { - cache[key] = undefined; - }; - - __exports__.ComputedProperty = ComputedProperty; - __exports__.computed = computed; - __exports__.cacheFor = cacheFor; - }); -enifed("ember-metal/computed_macros", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/is_empty","ember-metal/is_none","ember-metal/alias"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__) { - "use strict"; - var Ember = __dependency1__["default"]; - var get = __dependency2__.get; - var set = __dependency3__.set; - var computed = __dependency4__.computed; - var isEmpty = __dependency5__["default"]; - var isNone = __dependency6__["default"]; - var alias = __dependency7__["default"]; - - /** - @module ember-metal - */ - - var a_slice = [].slice; - - function getProperties(self, propertyNames) { - var ret = {}; - for(var i = 0; i < propertyNames.length; i++) { - ret[propertyNames[i]] = get(self, propertyNames[i]); - } - return ret; - } - - function registerComputed(name, macro) { - computed[name] = function(dependentKey) { - var args = a_slice.call(arguments); - return computed(dependentKey, function() { - return macro.apply(this, args); - }); - }; - } - - function registerComputedWithProperties(name, macro) { - computed[name] = function() { - var properties = a_slice.call(arguments); - - var computedFunc = computed(function() { - return macro.apply(this, [getProperties(this, properties)]); - }); - - return computedFunc.property.apply(computedFunc, properties); - }; - } - - /** - A computed property that returns true if the value of the dependent - property is null, an empty string, empty array, or empty function. - - Example - - ```javascript - var ToDoList = Ember.Object.extend({ - isDone: Ember.computed.empty('todos') - }); - - var todoList = ToDoList.create({ - todos: ['Unit Test', 'Documentation', 'Release'] - }); - - todoList.get('isDone'); // false - todoList.get('todos').clear(); - todoList.get('isDone'); // true - ``` - - @since 1.6.0 - @method computed.empty - @for Ember - @param {String} dependentKey - @return {Ember.ComputedProperty} computed property which negate - the original value for property - */ - computed.empty = function (dependentKey) { - return computed(dependentKey + '.length', function () { - return isEmpty(get(this, dependentKey)); - }); - }; - - /** - A computed property that returns true if the value of the dependent - property is NOT null, an empty string, empty array, or empty function. - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - hasStuff: Ember.computed.notEmpty('backpack') - }); - - var hamster = Hamster.create({ backpack: ['Food', 'Sleeping Bag', 'Tent'] }); - - hamster.get('hasStuff'); // true - hamster.get('backpack').clear(); // [] - hamster.get('hasStuff'); // false - ``` - - @method computed.notEmpty - @for Ember - @param {String} dependentKey - @return {Ember.ComputedProperty} computed property which returns true if - original value for property is not empty. - */ - computed.notEmpty = function(dependentKey) { - return computed(dependentKey + '.length', function () { - return !isEmpty(get(this, dependentKey)); - }); - }; - - /** - A computed property that returns true if the value of the dependent - property is null or undefined. This avoids errors from JSLint complaining - about use of ==, which can be technically confusing. - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - isHungry: Ember.computed.none('food') - }); - - var hamster = Hamster.create(); - - hamster.get('isHungry'); // true - hamster.set('food', 'Banana'); - hamster.get('isHungry'); // false - hamster.set('food', null); - hamster.get('isHungry'); // true - ``` - - @method computed.none - @for Ember - @param {String} dependentKey - @return {Ember.ComputedProperty} computed property which - returns true if original value for property is null or undefined. - */ - registerComputed('none', function(dependentKey) { - return isNone(get(this, dependentKey)); - }); - - /** - A computed property that returns the inverse boolean value - of the original value for the dependent property. - - Example - - ```javascript - var User = Ember.Object.extend({ - isAnonymous: Ember.computed.not('loggedIn') - }); - - var user = User.create({loggedIn: false}); - - user.get('isAnonymous'); // true - user.set('loggedIn', true); - user.get('isAnonymous'); // false - ``` - - @method computed.not - @for Ember - @param {String} dependentKey - @return {Ember.ComputedProperty} computed property which returns - inverse of the original value for property - */ - registerComputed('not', function(dependentKey) { - return !get(this, dependentKey); - }); - - /** - A computed property that converts the provided dependent property - into a boolean value. - - ```javascript - var Hamster = Ember.Object.extend({ - hasBananas: Ember.computed.bool('numBananas') - }); - - var hamster = Hamster.create(); - - hamster.get('hasBananas'); // false - hamster.set('numBananas', 0); - hamster.get('hasBananas'); // false - hamster.set('numBananas', 1); - hamster.get('hasBananas'); // true - hamster.set('numBananas', null); - hamster.get('hasBananas'); // false - ``` - - @method computed.bool - @for Ember - @param {String} dependentKey - @return {Ember.ComputedProperty} computed property which converts - to boolean the original value for property - */ - registerComputed('bool', function(dependentKey) { - return !!get(this, dependentKey); - }); - - /** - A computed property which matches the original value for the - dependent property against a given RegExp, returning `true` - if they values matches the RegExp and `false` if it does not. - - Example - - ```javascript - var User = Ember.Object.extend({ - hasValidEmail: Ember.computed.match('email', /^.+@.+\..+$/) - }); - - var user = User.create({loggedIn: false}); - - user.get('hasValidEmail'); // false - user.set('email', ''); - user.get('hasValidEmail'); // false - user.set('email', 'ember_hamster@example.com'); - user.get('hasValidEmail'); // true - ``` - - @method computed.match - @for Ember - @param {String} dependentKey - @param {RegExp} regexp - @return {Ember.ComputedProperty} computed property which match - the original value for property against a given RegExp - */ - registerComputed('match', function(dependentKey, regexp) { - var value = get(this, dependentKey); - return typeof value === 'string' ? regexp.test(value) : false; - }); - - /** - A computed property that returns true if the provided dependent property - is equal to the given value. - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - napTime: Ember.computed.equal('state', 'sleepy') - }); - - var hamster = Hamster.create(); - - hamster.get('napTime'); // false - hamster.set('state', 'sleepy'); - hamster.get('napTime'); // true - hamster.set('state', 'hungry'); - hamster.get('napTime'); // false - ``` - - @method computed.equal - @for Ember - @param {String} dependentKey - @param {String|Number|Object} value - @return {Ember.ComputedProperty} computed property which returns true if - the original value for property is equal to the given value. - */ - registerComputed('equal', function(dependentKey, value) { - return get(this, dependentKey) === value; - }); - - /** - A computed property that returns true if the provided dependent property - is greater than the provided value. - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - hasTooManyBananas: Ember.computed.gt('numBananas', 10) - }); - - var hamster = Hamster.create(); - - hamster.get('hasTooManyBananas'); // false - hamster.set('numBananas', 3); - hamster.get('hasTooManyBananas'); // false - hamster.set('numBananas', 11); - hamster.get('hasTooManyBananas'); // true - ``` - - @method computed.gt - @for Ember - @param {String} dependentKey - @param {Number} value - @return {Ember.ComputedProperty} computed property which returns true if - the original value for property is greater than given value. - */ - registerComputed('gt', function(dependentKey, value) { - return get(this, dependentKey) > value; - }); - - /** - A computed property that returns true if the provided dependent property - is greater than or equal to the provided value. - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - hasTooManyBananas: Ember.computed.gte('numBananas', 10) - }); - - var hamster = Hamster.create(); - - hamster.get('hasTooManyBananas'); // false - hamster.set('numBananas', 3); - hamster.get('hasTooManyBananas'); // false - hamster.set('numBananas', 10); - hamster.get('hasTooManyBananas'); // true - ``` - - @method computed.gte - @for Ember - @param {String} dependentKey - @param {Number} value - @return {Ember.ComputedProperty} computed property which returns true if - the original value for property is greater or equal then given value. - */ - registerComputed('gte', function(dependentKey, value) { - return get(this, dependentKey) >= value; - }); - - /** - A computed property that returns true if the provided dependent property - is less than the provided value. - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - needsMoreBananas: Ember.computed.lt('numBananas', 3) - }); - - var hamster = Hamster.create(); - - hamster.get('needsMoreBananas'); // true - hamster.set('numBananas', 3); - hamster.get('needsMoreBananas'); // false - hamster.set('numBananas', 2); - hamster.get('needsMoreBananas'); // true - ``` - - @method computed.lt - @for Ember - @param {String} dependentKey - @param {Number} value - @return {Ember.ComputedProperty} computed property which returns true if - the original value for property is less then given value. - */ - registerComputed('lt', function(dependentKey, value) { - return get(this, dependentKey) < value; - }); - - /** - A computed property that returns true if the provided dependent property - is less than or equal to the provided value. - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - needsMoreBananas: Ember.computed.lte('numBananas', 3) - }); - - var hamster = Hamster.create(); - - hamster.get('needsMoreBananas'); // true - hamster.set('numBananas', 5); - hamster.get('needsMoreBananas'); // false - hamster.set('numBananas', 3); - hamster.get('needsMoreBananas'); // true - ``` - - @method computed.lte - @for Ember - @param {String} dependentKey - @param {Number} value - @return {Ember.ComputedProperty} computed property which returns true if - the original value for property is less or equal than given value. - */ - registerComputed('lte', function(dependentKey, value) { - return get(this, dependentKey) <= value; - }); - - /** - A computed property that performs a logical `and` on the - original values for the provided dependent properties. - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - readyForCamp: Ember.computed.and('hasTent', 'hasBackpack') - }); - - var hamster = Hamster.create(); - - hamster.get('readyForCamp'); // false - hamster.set('hasTent', true); - hamster.get('readyForCamp'); // false - hamster.set('hasBackpack', true); - hamster.get('readyForCamp'); // true - ``` - - @method computed.and - @for Ember - @param {String} dependentKey* - @return {Ember.ComputedProperty} computed property which performs - a logical `and` on the values of all the original values for properties. - */ - registerComputedWithProperties('and', function(properties) { - for (var key in properties) { - if (properties.hasOwnProperty(key) && !properties[key]) { - return false; - } - } - return true; - }); - - /** - A computed property which performs a logical `or` on the - original values for the provided dependent properties. - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - readyForRain: Ember.computed.or('hasJacket', 'hasUmbrella') - }); - - var hamster = Hamster.create(); - - hamster.get('readyForRain'); // false - hamster.set('hasJacket', true); - hamster.get('readyForRain'); // true - ``` - - @method computed.or - @for Ember - @param {String} dependentKey* - @return {Ember.ComputedProperty} computed property which performs - a logical `or` on the values of all the original values for properties. - */ - registerComputedWithProperties('or', function(properties) { - for (var key in properties) { - if (properties.hasOwnProperty(key) && properties[key]) { - return true; - } - } - return false; - }); - - /** - A computed property that returns the first truthy value - from a list of dependent properties. - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - hasClothes: Ember.computed.any('hat', 'shirt') - }); - - var hamster = Hamster.create(); - - hamster.get('hasClothes'); // null - hamster.set('shirt', 'Hawaiian Shirt'); - hamster.get('hasClothes'); // 'Hawaiian Shirt' - ``` - - @method computed.any - @for Ember - @param {String} dependentKey* - @return {Ember.ComputedProperty} computed property which returns - the first truthy value of given list of properties. - */ - registerComputedWithProperties('any', function(properties) { - for (var key in properties) { - if (properties.hasOwnProperty(key) && properties[key]) { - return properties[key]; - } - } - return null; - }); - - /** - A computed property that returns the array of values - for the provided dependent properties. - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - clothes: Ember.computed.collect('hat', 'shirt') - }); - - var hamster = Hamster.create(); - - hamster.get('clothes'); // [null, null] - hamster.set('hat', 'Camp Hat'); - hamster.set('shirt', 'Camp Shirt'); - hamster.get('clothes'); // ['Camp Hat', 'Camp Shirt'] - ``` - - @method computed.collect - @for Ember - @param {String} dependentKey* - @return {Ember.ComputedProperty} computed property which maps - values of all passed in properties to an array. - */ - registerComputedWithProperties('collect', function(properties) { - var res = Ember.A(); - for (var key in properties) { - if (properties.hasOwnProperty(key)) { - if (isNone(properties[key])) { - res.push(null); - } else { - res.push(properties[key]); - } - } - } - return res; - }); - - /** - Creates a new property that is an alias for another property - on an object. Calls to `get` or `set` this property behave as - though they were called on the original property. - - ```javascript - var Person = Ember.Object.extend({ - name: 'Alex Matchneer', - nomen: Ember.computed.alias('name') - }); - - var alex = Person.create(); - - alex.get('nomen'); // 'Alex Matchneer' - alex.get('name'); // 'Alex Matchneer' - - alex.set('nomen', '@machty'); - alex.get('name'); // '@machty' - ``` - - @method computed.alias - @for Ember - @param {String} dependentKey - @return {Ember.ComputedProperty} computed property which creates an - alias to the original value for property. - */ - computed.alias = alias; - - /** - Where `computed.alias` aliases `get` and `set`, and allows for bidirectional - data flow, `computed.oneWay` only provides an aliased `get`. The `set` will - not mutate the upstream property, rather causes the current property to - become the value set. This causes the downstream property to permanently - diverge from the upstream property. - - Example - - ```javascript - var User = Ember.Object.extend({ - firstName: null, - lastName: null, - nickName: Ember.computed.oneWay('firstName') - }); - - var teddy = User.create({ - firstName: 'Teddy', - lastName: 'Zeenny' - }); - - teddy.get('nickName'); // 'Teddy' - teddy.set('nickName', 'TeddyBear'); // 'TeddyBear' - teddy.get('firstName'); // 'Teddy' - ``` - - @method computed.oneWay - @for Ember - @param {String} dependentKey - @return {Ember.ComputedProperty} computed property which creates a - one way computed property to the original value for property. - */ - computed.oneWay = function(dependentKey) { - return alias(dependentKey).oneWay(); - }; - - /** - This is a more semantically meaningful alias of `computed.oneWay`, - whose name is somewhat ambiguous as to which direction the data flows. - - @method computed.reads - @for Ember - @param {String} dependentKey - @return {Ember.ComputedProperty} computed property which creates a - one way computed property to the original value for property. - */ - computed.reads = computed.oneWay; - - /** - Where `computed.oneWay` provides oneWay bindings, `computed.readOnly` provides - a readOnly one way binding. Very often when using `computed.oneWay` one does - not also want changes to propagate back up, as they will replace the value. - - This prevents the reverse flow, and also throws an exception when it occurs. - - Example - - ```javascript - var User = Ember.Object.extend({ - firstName: null, - lastName: null, - nickName: Ember.computed.readOnly('firstName') - }); - - var teddy = User.create({ - firstName: 'Teddy', - lastName: 'Zeenny' - }); - - teddy.get('nickName'); // 'Teddy' - teddy.set('nickName', 'TeddyBear'); // throws Exception - // throw new Ember.Error('Cannot Set: nickName on: ' );` - teddy.get('firstName'); // 'Teddy' - ``` - - @method computed.readOnly - @for Ember - @param {String} dependentKey - @return {Ember.ComputedProperty} computed property which creates a - one way computed property to the original value for property. - @since 1.5.0 - */ - computed.readOnly = function(dependentKey) { - return alias(dependentKey).readOnly(); - }; - /** - A computed property that acts like a standard getter and setter, - but returns the value at the provided `defaultPath` if the - property itself has not been set to a value - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - wishList: Ember.computed.defaultTo('favoriteFood') - }); - - var hamster = Hamster.create({ favoriteFood: 'Banana' }); - - hamster.get('wishList'); // 'Banana' - hamster.set('wishList', 'More Unit Tests'); - hamster.get('wishList'); // 'More Unit Tests' - hamster.get('favoriteFood'); // 'Banana' - ``` - - @method computed.defaultTo - @for Ember - @param {String} defaultPath - @return {Ember.ComputedProperty} computed property which acts like - a standard getter and setter, but defaults to the value from `defaultPath`. - @deprecated Use `Ember.computed.oneWay` or custom CP with default instead. - */ - // ES6TODO: computed should have its own export path so you can do import {defaultTo} from computed - computed.defaultTo = function(defaultPath) { - return computed(function(key, newValue, cachedValue) { - Ember.deprecate('Usage of Ember.computed.defaultTo is deprecated, use `Ember.computed.oneWay` instead.'); - - if (arguments.length === 1) { - return get(this, defaultPath); - } - return newValue != null ? newValue : get(this, defaultPath); - }); - }; - - /** - Creates a new property that is an alias for another property - on an object. Calls to `get` or `set` this property behave as - though they were called on the original property, but also - print a deprecation warning. - - @method computed.deprecatingAlias - @for Ember - @param {String} dependentKey - @return {Ember.ComputedProperty} computed property which creates an - alias with a deprecation to the original value for property. - @since 1.7.0 - */ - computed.deprecatingAlias = function(dependentKey) { - return computed(dependentKey, function(key, value) { - Ember.deprecate('Usage of `' + key + '` is deprecated, use `' + dependentKey + '` instead.'); - - if (arguments.length > 1) { - set(this, dependentKey, value); - return value; - } else { - return get(this, dependentKey); - } - }); - }; - }); -enifed("ember-metal/core", - ["exports"], - function(__exports__) { - "use strict"; - /*globals Ember:true,ENV,EmberENV,MetamorphENV:true */ - - /** - @module ember - @submodule ember-metal - */ - - /** - All Ember methods and functions are defined inside of this namespace. You - generally should not add new properties to this namespace as it may be - overwritten by future versions of Ember. - - You can also use the shorthand `Em` instead of `Ember`. - - Ember-Runtime is a framework that provides core functions for Ember including - cross-platform functions, support for property observing and objects. Its - focus is on small size and performance. You can use this in place of or - along-side other cross-platform libraries such as jQuery. - - The core Runtime framework is based on the jQuery API with a number of - performance optimizations. - - @class Ember - @static - @version 1.10.1 - */ - - if ('undefined' === typeof Ember) { - // Create core object. Make it act like an instance of Ember.Namespace so that - // objects assigned to it are given a sane string representation. - Ember = {}; - } - - // Default imports, exports and lookup to the global object; - Ember.imports = Ember.imports || this; - Ember.lookup = Ember.lookup || this; - var exports = Ember.exports = Ember.exports || this; - - // aliases needed to keep minifiers from removing the global context - exports.Em = exports.Ember = Ember; - - // Make sure these are set whether Ember was already defined or not - - Ember.isNamespace = true; - - Ember.toString = function() { return "Ember"; }; - - - /** - @property VERSION - @type String - @default '1.10.1' - @static - */ - Ember.VERSION = '1.10.1'; - - /** - Standard environmental variables. You can define these in a global `EmberENV` - variable before loading Ember to control various configuration settings. - - For backwards compatibility with earlier versions of Ember the global `ENV` - variable will be used if `EmberENV` is not defined. - - @property ENV - @type Hash - */ - - if (Ember.ENV) { - // do nothing if Ember.ENV is already setup - } else if ('undefined' !== typeof EmberENV) { - Ember.ENV = EmberENV; - } else if('undefined' !== typeof ENV) { - Ember.ENV = ENV; - } else { - Ember.ENV = {}; - } - - Ember.config = Ember.config || {}; - - // We disable the RANGE API by default for performance reasons - if ('undefined' === typeof Ember.ENV.DISABLE_RANGE_API) { - Ember.ENV.DISABLE_RANGE_API = true; - } - - if ("undefined" === typeof MetamorphENV) { - exports.MetamorphENV = {}; - } - - MetamorphENV.DISABLE_RANGE_API = Ember.ENV.DISABLE_RANGE_API; - - /** - Hash of enabled Canary features. Add to this before creating your application. - - You can also define `EmberENV.FEATURES` if you need to enable features flagged at runtime. - - @class FEATURES - @namespace Ember - @static - @since 1.1.0 - */ - - Ember.FEATURES = Ember.ENV.FEATURES || {}; - - /** - Test that a feature is enabled. Parsed by Ember's build tools to leave - experimental features out of beta/stable builds. - - You can define the following configuration options: - - * `EmberENV.ENABLE_ALL_FEATURES` - force all features to be enabled. - * `EmberENV.ENABLE_OPTIONAL_FEATURES` - enable any features that have not been explicitly - enabled/disabled. - - @method isEnabled - @param {String} feature - @return {Boolean} - @for Ember.FEATURES - @since 1.1.0 - */ - - Ember.FEATURES.isEnabled = function(feature) { - var featureValue = Ember.FEATURES[feature]; - - if (Ember.ENV.ENABLE_ALL_FEATURES) { - return true; - } else if (featureValue === true || featureValue === false || featureValue === undefined) { - return featureValue; - } else if (Ember.ENV.ENABLE_OPTIONAL_FEATURES) { - return true; - } else { - return false; - } - }; - - // .......................................................... - // BOOTSTRAP - // - - /** - Determines whether Ember should enhance some built-in object prototypes to - provide a more friendly API. If enabled, a few methods will be added to - `Function`, `String`, and `Array`. `Object.prototype` will not be enhanced, - which is the one that causes most trouble for people. - - In general we recommend leaving this option set to true since it rarely - conflicts with other code. If you need to turn it off however, you can - define an `EmberENV.EXTEND_PROTOTYPES` config to disable it. - - @property EXTEND_PROTOTYPES - @type Boolean - @default true - @for Ember - */ - Ember.EXTEND_PROTOTYPES = Ember.ENV.EXTEND_PROTOTYPES; - - if (typeof Ember.EXTEND_PROTOTYPES === 'undefined') { - Ember.EXTEND_PROTOTYPES = true; - } - - /** - Determines whether Ember logs a full stack trace during deprecation warnings - - @property LOG_STACKTRACE_ON_DEPRECATION - @type Boolean - @default true - */ - Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !== false); - - /** - Determines whether Ember should add ECMAScript 5 Array shims to older browsers. - - @property SHIM_ES5 - @type Boolean - @default Ember.EXTEND_PROTOTYPES - */ - Ember.SHIM_ES5 = (Ember.ENV.SHIM_ES5 === false) ? false : Ember.EXTEND_PROTOTYPES; - - /** - Determines whether Ember logs info about version of used libraries - - @property LOG_VERSION - @type Boolean - @default true - */ - Ember.LOG_VERSION = (Ember.ENV.LOG_VERSION === false) ? false : true; - - /** - Empty function. Useful for some operations. Always returns `this`. - - @method K - @private - @return {Object} - */ - function K() { return this; } - __exports__.K = K; - Ember.K = K; - //TODO: ES6 GLOBAL TODO - - // Stub out the methods defined by the ember-debug package in case it's not loaded - - if ('undefined' === typeof Ember.assert) { Ember.assert = K; } - if ('undefined' === typeof Ember.warn) { Ember.warn = K; } - if ('undefined' === typeof Ember.debug) { Ember.debug = K; } - if ('undefined' === typeof Ember.runInDebug) { Ember.runInDebug = K; } - if ('undefined' === typeof Ember.deprecate) { Ember.deprecate = K; } - if ('undefined' === typeof Ember.deprecateFunc) { - Ember.deprecateFunc = function(_, func) { return func; }; - } - - __exports__["default"] = Ember; - }); -enifed("ember-metal/dependent_keys", - ["ember-metal/platform","ember-metal/watching","exports"], - function(__dependency1__, __dependency2__, __exports__) { - // Remove "use strict"; from transpiled module until - // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed - // - // REMOVE_USE_STRICT: true - - var o_create = __dependency1__.create; - var watch = __dependency2__.watch; - var unwatch = __dependency2__.unwatch; - - /** - @module ember-metal - */ - - // .......................................................... - // DEPENDENT KEYS - // - - // data structure: - // meta.deps = { - // 'depKey': { - // 'keyName': count, - // } - // } - - /* - This function returns a map of unique dependencies for a - given object and key. - */ - function keysForDep(depsMeta, depKey) { - var keys = depsMeta[depKey]; - if (!keys) { - // if there are no dependencies yet for a the given key - // create a new empty list of dependencies for the key - keys = depsMeta[depKey] = {}; - } else if (!depsMeta.hasOwnProperty(depKey)) { - // otherwise if the dependency list is inherited from - // a superclass, clone the hash - keys = depsMeta[depKey] = o_create(keys); - } - return keys; - } - - function metaForDeps(meta) { - return keysForDep(meta, 'deps'); - } - - function addDependentKeys(desc, obj, keyName, meta) { - // the descriptor has a list of dependent keys, so - // add all of its dependent keys. - var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; - if (!depKeys) return; - - depsMeta = metaForDeps(meta); - - for(idx = 0, len = depKeys.length; idx < len; idx++) { - depKey = depKeys[idx]; - // Lookup keys meta for depKey - keys = keysForDep(depsMeta, depKey); - // Increment the number of times depKey depends on keyName. - keys[keyName] = (keys[keyName] || 0) + 1; - // Watch the depKey - watch(obj, depKey, meta); - } - } - - __exports__.addDependentKeys = addDependentKeys;function removeDependentKeys(desc, obj, keyName, meta) { - // the descriptor has a list of dependent keys, so - // remove all of its dependent keys. - var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; - if (!depKeys) return; - - depsMeta = metaForDeps(meta); - - for(idx = 0, len = depKeys.length; idx < len; idx++) { - depKey = depKeys[idx]; - // Lookup keys meta for depKey - keys = keysForDep(depsMeta, depKey); - // Decrement the number of times depKey depends on keyName. - keys[keyName] = (keys[keyName] || 0) - 1; - // Unwatch the depKey - unwatch(obj, depKey, meta); - } - } - - __exports__.removeDependentKeys = removeDependentKeys; - }); -enifed("ember-metal/deprecate_property", - ["ember-metal/core","ember-metal/platform","ember-metal/properties","ember-metal/property_get","ember-metal/property_set","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - /** - @module ember-metal - */ - - var Ember = __dependency1__["default"]; - var hasPropertyAccessors = __dependency2__.hasPropertyAccessors; - var defineProperty = __dependency3__.defineProperty; - var get = __dependency4__.get; - var set = __dependency5__.set; - - - /** - Used internally to allow changing properties in a backwards compatible way, and print a helpful - deprecation warning. - - @method deprecateProperty - @param {Object} object The object to add the deprecated property to. - @param {String} deprecatedKey The property to add (and print deprecation warnings upon accessing). - @param {String} newKey The property that will be aliased. - @private - @since 1.7.0 - */ - - function deprecateProperty(object, deprecatedKey, newKey) { - function deprecate() { - Ember.deprecate('Usage of `' + deprecatedKey + '` is deprecated, use `' + newKey + '` instead.'); - } - - if (hasPropertyAccessors) { - defineProperty(object, deprecatedKey, { - configurable: true, - enumerable: false, - set: function(value) { deprecate(); set(this, newKey, value); }, - get: function() { deprecate(); return get(this, newKey); } - }); - } - } - - __exports__.deprecateProperty = deprecateProperty; - }); -enifed("ember-metal/dictionary", - ["ember-metal/platform","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var create = __dependency1__.create; - - // the delete is meant to hint at runtimes that this object should remain in - // dictionary mode. This is clearly a runtime specific hack, but currently it - // appears worthwile in some usecases. Please note, these deletes do increase - // the cost of creation dramatically over a plain Object.create. And as this - // only makes sense for long-lived dictionaries that aren't instantiated often. - __exports__["default"] = function makeDictionary(parent) { - var dict = create(parent); - dict['_dict'] = null; - delete dict['_dict']; - return dict; - } - }); -enifed("ember-metal/enumerable_utils", - ["ember-metal/array","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var _filter = __dependency1__.filter; - var a_forEach = __dependency1__.forEach; - var _indexOf = __dependency1__.indexOf; - var _map = __dependency1__.map; - - var splice = Array.prototype.splice; - - /** - * Defines some convenience methods for working with Enumerables. - * `Ember.EnumerableUtils` uses `Ember.ArrayPolyfills` when necessary. - * - * @class EnumerableUtils - * @namespace Ember - * @static - * */ - - /** - * Calls the map function on the passed object with a specified callback. This - * uses `Ember.ArrayPolyfill`'s-map method when necessary. - * - * @method map - * @param {Object} obj The object that should be mapped - * @param {Function} callback The callback to execute - * @param {Object} thisArg Value to use as this when executing *callback* - * - * @return {Array} An array of mapped values. - */ - function map(obj, callback, thisArg) { - return obj.map ? obj.map(callback, thisArg) : _map.call(obj, callback, thisArg); - } - - __exports__.map = map;/** - * Calls the forEach function on the passed object with a specified callback. This - * uses `Ember.ArrayPolyfill`'s-forEach method when necessary. - * - * @method forEach - * @param {Object} obj The object to call forEach on - * @param {Function} callback The callback to execute - * @param {Object} thisArg Value to use as this when executing *callback* - * - */ - function forEach(obj, callback, thisArg) { - return obj.forEach ? obj.forEach(callback, thisArg) : a_forEach.call(obj, callback, thisArg); - } - - __exports__.forEach = forEach;/** - * Calls the filter function on the passed object with a specified callback. This - * uses `Ember.ArrayPolyfill`'s-filter method when necessary. - * - * @method filter - * @param {Object} obj The object to call filter on - * @param {Function} callback The callback to execute - * @param {Object} thisArg Value to use as this when executing *callback* - * - * @return {Array} An array containing the filtered values - * @since 1.4.0 - */ - function filter(obj, callback, thisArg) { - return obj.filter ? obj.filter(callback, thisArg) : _filter.call(obj, callback, thisArg); - } - - __exports__.filter = filter;/** - * Calls the indexOf function on the passed object with a specified callback. This - * uses `Ember.ArrayPolyfill`'s-indexOf method when necessary. - * - * @method indexOf - * @param {Object} obj The object to call indexOn on - * @param {Function} callback The callback to execute - * @param {Object} index The index to start searching from - * - */ - function indexOf(obj, element, index) { - return obj.indexOf ? obj.indexOf(element, index) : _indexOf.call(obj, element, index); - } - - __exports__.indexOf = indexOf;/** - * Returns an array of indexes of the first occurrences of the passed elements - * on the passed object. - * - * ```javascript - * var array = [1, 2, 3, 4, 5]; - * Ember.EnumerableUtils.indexesOf(array, [2, 5]); // [1, 4] - * - * var fubar = "Fubarr"; - * Ember.EnumerableUtils.indexesOf(fubar, ['b', 'r']); // [2, 4] - * ``` - * - * @method indexesOf - * @param {Object} obj The object to check for element indexes - * @param {Array} elements The elements to search for on *obj* - * - * @return {Array} An array of indexes. - * - */ - function indexesOf(obj, elements) { - return elements === undefined ? [] : map(elements, function(item) { - return indexOf(obj, item); - }); - } - - __exports__.indexesOf = indexesOf;/** - * Adds an object to an array. If the array already includes the object this - * method has no effect. - * - * @method addObject - * @param {Array} array The array the passed item should be added to - * @param {Object} item The item to add to the passed array - * - * @return 'undefined' - */ - function addObject(array, item) { - var index = indexOf(array, item); - if (index === -1) { array.push(item); } - } - - __exports__.addObject = addObject;/** - * Removes an object from an array. If the array does not contain the passed - * object this method has no effect. - * - * @method removeObject - * @param {Array} array The array to remove the item from. - * @param {Object} item The item to remove from the passed array. - * - * @return 'undefined' - */ - function removeObject(array, item) { - var index = indexOf(array, item); - if (index !== -1) { array.splice(index, 1); } - } - - __exports__.removeObject = removeObject;function _replace(array, idx, amt, objects) { - var args = [].concat(objects); - var ret = []; - // https://code.google.com/p/chromium/issues/detail?id=56588 - var size = 60000; - var start = idx; - var ends = amt; - var count, chunk; - - while (args.length) { - count = ends > size ? size : ends; - if (count <= 0) { count = 0; } - - chunk = args.splice(0, size); - chunk = [start, count].concat(chunk); - - start += size; - ends -= count; - - ret = ret.concat(splice.apply(array, chunk)); - } - return ret; - } - - __exports__._replace = _replace;/** - * Replaces objects in an array with the passed objects. - * - * ```javascript - * var array = [1,2,3]; - * Ember.EnumerableUtils.replace(array, 1, 2, [4, 5]); // [1, 4, 5] - * - * var array = [1,2,3]; - * Ember.EnumerableUtils.replace(array, 1, 1, [4, 5]); // [1, 4, 5, 3] - * - * var array = [1,2,3]; - * Ember.EnumerableUtils.replace(array, 10, 1, [4, 5]); // [1, 2, 3, 4, 5] - * ``` - * - * @method replace - * @param {Array} array The array the objects should be inserted into. - * @param {Number} idx Starting index in the array to replace. If *idx* >= - * length, then append to the end of the array. - * @param {Number} amt Number of elements that should be removed from the array, - * starting at *idx* - * @param {Array} objects An array of zero or more objects that should be - * inserted into the array at *idx* - * - * @return {Array} The modified array. - */ - function replace(array, idx, amt, objects) { - if (array.replace) { - return array.replace(idx, amt, objects); - } else { - return _replace(array, idx, amt, objects); - } - } - - __exports__.replace = replace;/** - * Calculates the intersection of two arrays. This method returns a new array - * filled with the records that the two passed arrays share with each other. - * If there is no intersection, an empty array will be returned. - * - * ```javascript - * var array1 = [1, 2, 3, 4, 5]; - * var array2 = [1, 3, 5, 6, 7]; - * - * Ember.EnumerableUtils.intersection(array1, array2); // [1, 3, 5] - * - * var array1 = [1, 2, 3]; - * var array2 = [4, 5, 6]; - * - * Ember.EnumerableUtils.intersection(array1, array2); // [] - * ``` - * - * @method intersection - * @param {Array} array1 The first array - * @param {Array} array2 The second array - * - * @return {Array} The intersection of the two passed arrays. - */ - function intersection(array1, array2) { - var result = []; - forEach(array1, function(element) { - if (indexOf(array2, element) >= 0) { - result.push(element); - } - }); - - return result; - } - - __exports__.intersection = intersection;// TODO: this only exists to maintain the existing api, as we move forward it - // should only be part of the "global build" via some shim - __exports__["default"] = { - _replace: _replace, - addObject: addObject, - filter: filter, - forEach: forEach, - indexOf: indexOf, - indexesOf: indexesOf, - intersection: intersection, - map: map, - removeObject: removeObject, - replace: replace - }; - }); -enifed("ember-metal/error", - ["ember-metal/platform","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var create = __dependency1__.create; - - var errorProps = [ - 'description', - 'fileName', - 'lineNumber', - 'message', - 'name', - 'number', - 'stack' - ]; - - /** - A subclass of the JavaScript Error object for use in Ember. - - @class Error - @namespace Ember - @extends Error - @constructor - */ - function EmberError() { - var tmp = Error.apply(this, arguments); - - // Adds a `stack` property to the given error object that will yield the - // stack trace at the time captureStackTrace was called. - // When collecting the stack trace all frames above the topmost call - // to this function, including that call, will be left out of the - // stack trace. - // This is useful because we can hide Ember implementation details - // that are not very helpful for the user. - if (Error.captureStackTrace) { - Error.captureStackTrace(this, Ember.Error); - } - // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. - for (var idx = 0; idx < errorProps.length; idx++) { - this[errorProps[idx]] = tmp[errorProps[idx]]; - } - } - - EmberError.prototype = create(Error.prototype); - - __exports__["default"] = EmberError; - }); -enifed("ember-metal/events", - ["ember-metal/core","ember-metal/utils","ember-metal/platform","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - // Remove "use strict"; from transpiled module until - // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed - // - // REMOVE_USE_STRICT: true - - /** - @module ember-metal - */ - var Ember = __dependency1__["default"]; - var metaFor = __dependency2__.meta; - var tryFinally = __dependency2__.tryFinally; - var apply = __dependency2__.apply; - var applyStr = __dependency2__.applyStr; - var create = __dependency3__.create; - - var a_slice = [].slice; - - /* listener flags */ - var ONCE = 1; - var SUSPENDED = 2; - - - /* - The event system uses a series of nested hashes to store listeners on an - object. When a listener is registered, or when an event arrives, these - hashes are consulted to determine which target and action pair to invoke. - - The hashes are stored in the object's meta hash, and look like this: - - // Object's meta hash - { - listeners: { // variable name: `listenerSet` - "foo:changed": [ // variable name: `actions` - target, method, flags - ] - } - } - - */ - - function indexOf(array, target, method) { - var index = -1; - // hashes are added to the end of the event array - // so it makes sense to start searching at the end - // of the array and search in reverse - for (var i = array.length - 3 ; i >=0; i -= 3) { - if (target === array[i] && method === array[i + 1]) { - index = i; break; - } - } - return index; - } - - function actionsFor(obj, eventName) { - var meta = metaFor(obj, true); - var actions; - var listeners = meta.listeners; - - if (!listeners) { - listeners = meta.listeners = create(null); - listeners.__source__ = obj; - } else if (listeners.__source__ !== obj) { - // setup inherited copy of the listeners object - listeners = meta.listeners = create(listeners); - listeners.__source__ = obj; - } - - actions = listeners[eventName]; - - // if there are actions, but the eventName doesn't exist in our listeners, then copy them from the prototype - if (actions && actions.__source__ !== obj) { - actions = listeners[eventName] = listeners[eventName].slice(); - actions.__source__ = obj; - } else if (!actions) { - actions = listeners[eventName] = []; - actions.__source__ = obj; - } - - return actions; - } - - function accumulateListeners(obj, eventName, otherActions) { - var meta = obj['__ember_meta__']; - var actions = meta && meta.listeners && meta.listeners[eventName]; - - if (!actions) { return; } - - var newActions = []; - - for (var i = actions.length - 3; i >= 0; i -= 3) { - var target = actions[i]; - var method = actions[i+1]; - var flags = actions[i+2]; - var actionIndex = indexOf(otherActions, target, method); - - if (actionIndex === -1) { - otherActions.push(target, method, flags); - newActions.push(target, method, flags); - } - } - - return newActions; - } - - __exports__.accumulateListeners = accumulateListeners;/** - Add an event listener - - @method addListener - @for Ember - @param obj - @param {String} eventName - @param {Object|Function} target A target object or a function - @param {Function|String} method A function or the name of a function to be called on `target` - @param {Boolean} once A flag whether a function should only be called once - */ - function addListener(obj, eventName, target, method, once) { - Ember.assert("You must pass at least an object and event name to Ember.addListener", !!obj && !!eventName); - - if (!method && 'function' === typeof target) { - method = target; - target = null; - } - - var actions = actionsFor(obj, eventName); - var actionIndex = indexOf(actions, target, method); - var flags = 0; - - if (once) flags |= ONCE; - - if (actionIndex !== -1) { return; } - - actions.push(target, method, flags); - - if ('function' === typeof obj.didAddListener) { - obj.didAddListener(eventName, target, method); - } - } - - __exports__.addListener = addListener;/** - Remove an event listener - - Arguments should match those passed to `Ember.addListener`. - - @method removeListener - @for Ember - @param obj - @param {String} eventName - @param {Object|Function} target A target object or a function - @param {Function|String} method A function or the name of a function to be called on `target` - */ - function removeListener(obj, eventName, target, method) { - Ember.assert("You must pass at least an object and event name to Ember.removeListener", !!obj && !!eventName); - - if (!method && 'function' === typeof target) { - method = target; - target = null; - } - - function _removeListener(target, method) { - var actions = actionsFor(obj, eventName); - var actionIndex = indexOf(actions, target, method); - - // action doesn't exist, give up silently - if (actionIndex === -1) { return; } - - actions.splice(actionIndex, 3); - - if ('function' === typeof obj.didRemoveListener) { - obj.didRemoveListener(eventName, target, method); - } - } - - if (method) { - _removeListener(target, method); - } else { - var meta = obj['__ember_meta__']; - var actions = meta && meta.listeners && meta.listeners[eventName]; - - if (!actions) { return; } - for (var i = actions.length - 3; i >= 0; i -= 3) { - _removeListener(actions[i], actions[i+1]); - } - } - } - - /** - Suspend listener during callback. - - This should only be used by the target of the event listener - when it is taking an action that would cause the event, e.g. - an object might suspend its property change listener while it is - setting that property. - - @method suspendListener - @for Ember - - @private - @param obj - @param {String} eventName - @param {Object|Function} target A target object or a function - @param {Function|String} method A function or the name of a function to be called on `target` - @param {Function} callback - */ - function suspendListener(obj, eventName, target, method, callback) { - if (!method && 'function' === typeof target) { - method = target; - target = null; - } - - var actions = actionsFor(obj, eventName); - var actionIndex = indexOf(actions, target, method); - - if (actionIndex !== -1) { - actions[actionIndex+2] |= SUSPENDED; // mark the action as suspended - } - - function tryable() { return callback.call(target); } - function finalizer() { if (actionIndex !== -1) { actions[actionIndex+2] &= ~SUSPENDED; } } - - return tryFinally(tryable, finalizer); - } - - __exports__.suspendListener = suspendListener;/** - Suspends multiple listeners during a callback. - - @method suspendListeners - @for Ember - - @private - @param obj - @param {Array} eventNames Array of event names - @param {Object|Function} target A target object or a function - @param {Function|String} method A function or the name of a function to be called on `target` - @param {Function} callback - */ - function suspendListeners(obj, eventNames, target, method, callback) { - if (!method && 'function' === typeof target) { - method = target; - target = null; - } - - var suspendedActions = []; - var actionsList = []; - var eventName, actions, i, l; - - for (i=0, l=eventNames.length; i= 0; i -= 3) { // looping in reverse for once listeners - var target = actions[i], method = actions[i+1], flags = actions[i+2]; - if (!method) { continue; } - if (flags & SUSPENDED) { continue; } - if (flags & ONCE) { removeListener(obj, eventName, target, method); } - if (!target) { target = obj; } - if ('string' === typeof method) { - if (params) { - applyStr(target, method, params); - } else { - target[method](); - } - } else { - if (params) { - apply(target, method, params); - } else { - method.call(target); - } - } - } - return true; - } - - __exports__.sendEvent = sendEvent;/** - @private - @method hasListeners - @for Ember - @param obj - @param {String} eventName - */ - function hasListeners(obj, eventName) { - var meta = obj['__ember_meta__']; - var actions = meta && meta.listeners && meta.listeners[eventName]; - - return !!(actions && actions.length); - } - - __exports__.hasListeners = hasListeners;/** - @private - @method listenersFor - @for Ember - @param obj - @param {String} eventName - */ - function listenersFor(obj, eventName) { - var ret = []; - var meta = obj['__ember_meta__']; - var actions = meta && meta.listeners && meta.listeners[eventName]; - - if (!actions) { return ret; } - - for (var i = 0, l = actions.length; i < l; i += 3) { - var target = actions[i]; - var method = actions[i+1]; - ret.push([target, method]); - } - - return ret; - } - - __exports__.listenersFor = listenersFor;/** - Define a property as a function that should be executed when - a specified event or events are triggered. - - - ``` javascript - var Job = Ember.Object.extend({ - logCompleted: Ember.on('completed', function() { - console.log('Job completed!'); - }) - }); - - var job = Job.create(); - - Ember.sendEvent(job, 'completed'); // Logs 'Job completed!' - ``` - - @method on - @for Ember - @param {String} eventNames* - @param {Function} func - @return func - */ - function on(){ - var func = a_slice.call(arguments, -1)[0]; - var events = a_slice.call(arguments, 0, -1); - func.__ember_listens__ = events; - return func; - } - - __exports__.on = on;__exports__.removeListener = removeListener; - }); -enifed("ember-metal/expand_properties", - ["ember-metal/core","ember-metal/error","ember-metal/enumerable_utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var EmberError = __dependency2__["default"]; - var forEach = __dependency3__.forEach; - - /** - @module ember-metal - */ - - var BRACE_EXPANSION = /^((?:[^\.]*\.)*)\{(.*)\}$/; - var SPLIT_REGEX = /\{|\}/; - - /** - Expands `pattern`, invoking `callback` for each expansion. - - The only pattern supported is brace-expansion, anything else will be passed - once to `callback` directly. - - Example - - ```js - function echo(arg){ console.log(arg); } - - Ember.expandProperties('foo.bar', echo); //=> 'foo.bar' - Ember.expandProperties('{foo,bar}', echo); //=> 'foo', 'bar' - Ember.expandProperties('foo.{bar,baz}', echo); //=> 'foo.bar', 'foo.baz' - Ember.expandProperties('{foo,bar}.baz', echo); //=> '{foo,bar}.baz' - Ember.expandProperties('foo.{bar,baz}.@each', echo) //=> 'foo.bar.@each', 'foo.baz.@each' - Ember.expandProperties('{foo,bar}.{spam,eggs}', echo) //=> 'foo.spam', 'foo.eggs', 'bar.spam', 'bar.eggs' - Ember.expandProperties('{foo}.bar.{baz}') //=> 'foo.bar.baz' - ``` - - @method - @private - @param {String} pattern The property pattern to expand. - @param {Function} callback The callback to invoke. It is invoked once per - expansion, and is passed the expansion. - */ - __exports__["default"] = function expandProperties(pattern, callback) { - if (pattern.indexOf(' ') > -1) { - throw new EmberError('Brace expanded properties cannot contain spaces, ' + - 'e.g. `user.{firstName, lastName}` should be `user.{firstName,lastName}`'); - } - - - return newExpandProperties(pattern, callback); - } - - function oldExpandProperties(pattern, callback) { - var match, prefix, list; - - if (match = BRACE_EXPANSION.exec(pattern)) { - prefix = match[1]; - list = match[2]; - - forEach(list.split(','), function (suffix) { - callback(prefix + suffix); - }); - } else { - callback(pattern); - } - } - - function newExpandProperties(pattern, callback) { - if ('string' === Ember.typeOf(pattern)) { - var parts = pattern.split(SPLIT_REGEX); - var properties = [parts]; - - forEach(parts, function(part, index) { - if (part.indexOf(',') >= 0) { - properties = duplicateAndReplace(properties, part.split(','), index); - } - }); - - forEach(properties, function(property) { - callback(property.join('')); - }); - } else { - callback(pattern); - } - } - - function duplicateAndReplace(properties, currentParts, index) { - var all = []; - - forEach(properties, function(property) { - forEach(currentParts, function(part) { - var current = property.slice(0); - current[index] = part; - all.push(current); - }); - }); - - return all; - } - }); -enifed("ember-metal/get_properties", - ["ember-metal/property_get","ember-metal/utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var get = __dependency1__.get; - var typeOf = __dependency2__.typeOf; - - /** - To get multiple properties at once, call `Ember.getProperties` - with an object followed by a list of strings or an array: - - ```javascript - Ember.getProperties(record, 'firstName', 'lastName', 'zipCode'); - // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } - ``` - - is equivalent to: - - ```javascript - Ember.getProperties(record, ['firstName', 'lastName', 'zipCode']); - // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } - ``` - - @method getProperties - @for Ember - @param {Object} obj - @param {String...|Array} list of keys to get - @return {Object} - */ - __exports__["default"] = function getProperties(obj) { - var ret = {}; - var propertyNames = arguments; - var i = 1; - - if (arguments.length === 2 && typeOf(arguments[1]) === 'array') { - i = 0; - propertyNames = arguments[1]; - } - for(var len = propertyNames.length; i < len; i++) { - ret[propertyNames[i]] = get(obj, propertyNames[i]); - } - return ret; - } - }); -enifed("ember-metal/injected_property", - ["ember-metal/core","ember-metal/computed","ember-metal/alias","ember-metal/properties","ember-metal/platform","ember-metal/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - var ComputedProperty = __dependency2__.ComputedProperty; - var AliasedProperty = __dependency3__.AliasedProperty; - var Descriptor = __dependency4__.Descriptor; - var create = __dependency5__.create; - var meta = __dependency6__.meta; - - /** - Read-only property that returns the result of a container lookup. - - @class InjectedProperty - @namespace Ember - @extends Ember.Descriptor - @constructor - @param {String} type The container type the property will lookup - @param {String} name (optional) The name the property will lookup, defaults - to the property's name - */ - function InjectedProperty(type, name) { - this.type = type; - this.name = name; - - this._super$Constructor(injectedPropertyGet); - AliasedPropertyPrototype.oneWay.call(this); - } - - function injectedPropertyGet(keyName) { - var desc = meta(this).descs[keyName]; - - Ember.assert("Attempting to lookup an injected property on an object " + - "without a container, ensure that the object was " + - "instantiated via a container.", this.container); - - return this.container.lookup(desc.type + ':' + (desc.name || keyName)); - } - - InjectedProperty.prototype = create(Descriptor.prototype); - - var InjectedPropertyPrototype = InjectedProperty.prototype; - var ComputedPropertyPrototype = ComputedProperty.prototype; - var AliasedPropertyPrototype = AliasedProperty.prototype; - - InjectedPropertyPrototype._super$Constructor = ComputedProperty; - - InjectedPropertyPrototype.get = ComputedPropertyPrototype.get; - InjectedPropertyPrototype.readOnly = ComputedPropertyPrototype.readOnly; - - InjectedPropertyPrototype.teardown = ComputedPropertyPrototype.teardown; - - __exports__["default"] = InjectedProperty; - }); -enifed("ember-metal/instrumentation", - ["ember-metal/core","ember-metal/utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var tryCatchFinally = __dependency2__.tryCatchFinally; - - /** - The purpose of the Ember Instrumentation module is - to provide efficient, general-purpose instrumentation - for Ember. - - Subscribe to a listener by using `Ember.subscribe`: - - ```javascript - Ember.subscribe("render", { - before: function(name, timestamp, payload) { - - }, - - after: function(name, timestamp, payload) { - - } - }); - ``` - - If you return a value from the `before` callback, that same - value will be passed as a fourth parameter to the `after` - callback. - - Instrument a block of code by using `Ember.instrument`: - - ```javascript - Ember.instrument("render.handlebars", payload, function() { - // rendering logic - }, binding); - ``` - - Event names passed to `Ember.instrument` are namespaced - by periods, from more general to more specific. Subscribers - can listen for events by whatever level of granularity they - are interested in. - - In the above example, the event is `render.handlebars`, - and the subscriber listened for all events beginning with - `render`. It would receive callbacks for events named - `render`, `render.handlebars`, `render.container`, or - even `render.handlebars.layout`. - - @class Instrumentation - @namespace Ember - @static - */ - var subscribers = []; - __exports__.subscribers = subscribers;var cache = {}; - - var populateListeners = function(name) { - var listeners = []; - var subscriber; - - for (var i=0, l=subscribers.length; i -1) { - list.splice(index, 1); - } - this.size = list.length; - return true; - } else { - return false; - } - }, - - /** - @method isEmpty - @return {Boolean} - */ - isEmpty: function() { - return this.size === 0; - }, - - /** - @method has - @param obj - @return {Boolean} - */ - has: function(obj) { - if (this.size === 0) { return false; } - - var guid = guidFor(obj); - var presenceSet = this.presenceSet; - - return presenceSet[guid] === true; - }, - - /** - @method forEach - @param {Function} fn - @param self - */ - forEach: function(fn /*, thisArg*/) { - if (typeof fn !== 'function') { - missingFunction(fn); - } - - if (this.size === 0) { return; } - - var list = this.list; - var length = arguments.length; - var i; - - if (length === 2) { - for (i = 0; i < list.length; i++) { - fn.call(arguments[1], list[i]); - } - } else { - for (i = 0; i < list.length; i++) { - fn(list[i]); - } - } - }, - - /** - @method toArray - @return {Array} - */ - toArray: function() { - return this.list.slice(); - }, - - /** - @method copy - @return {Ember.OrderedSet} - */ - copy: function() { - var Constructor = this.constructor; - var set = new Constructor(); - - set._silenceRemoveDeprecation = this._silenceRemoveDeprecation; - set.presenceSet = copyNull(this.presenceSet); - set.list = this.toArray(); - set.size = this.size; - - return set; - } - }; - - deprecateProperty(OrderedSet.prototype, 'length', 'size'); - - /** - A Map stores values indexed by keys. Unlike JavaScript's - default Objects, the keys of a Map can be any JavaScript - object. - - Internally, a Map has two data structures: - - 1. `keys`: an OrderedSet of all of the existing keys - 2. `values`: a JavaScript Object indexed by the `Ember.guidFor(key)` - - When a key/value pair is added for the first time, we - add the key to the `keys` OrderedSet, and create or - replace an entry in `values`. When an entry is deleted, - we delete its entry in `keys` and `values`. - - @class Map - @namespace Ember - @private - @constructor - */ - function Map() { - if (this instanceof this.constructor) { - this.keys = OrderedSet.create(); - this.keys._silenceRemoveDeprecation = true; - this.values = create(null); - this.size = 0; - } else { - missingNew("OrderedSet"); - } - } - - Ember.Map = Map; - - /** - @method create - @static - */ - Map.create = function() { - var Constructor = this; - return new Constructor(); - }; - - Map.prototype = { - constructor: Map, - - /** - This property will change as the number of objects in the map changes. - - @since 1.8.0 - @property size - @type number - @default 0 - */ - size: 0, - - /** - Retrieve the value associated with a given key. - - @method get - @param {*} key - @return {*} the value associated with the key, or `undefined` - */ - get: function(key) { - if (this.size === 0) { return; } - - var values = this.values; - var guid = guidFor(key); - - return values[guid]; - }, - - /** - Adds a value to the map. If a value for the given key has already been - provided, the new value will replace the old value. - - @method set - @param {*} key - @param {*} value - @return {Ember.Map} - */ - set: function(key, value) { - var keys = this.keys; - var values = this.values; - var guid = guidFor(key); - - // ensure we don't store -0 - var k = key === -0 ? 0 : key; - - keys.add(k, guid); - - values[guid] = value; - - this.size = keys.size; - - return this; - }, - - /** - @deprecated see delete - Removes a value from the map for an associated key. - - @method remove - @param {*} key - @return {Boolean} true if an item was removed, false otherwise - */ - remove: function(key) { - Ember.deprecate('Calling `Map.prototype.remove` has been deprecated, please use `Map.prototype.delete` instead.'); - - return this["delete"](key); - }, - - /** - Removes a value from the map for an associated key. - - @since 1.8.0 - @method delete - @param {*} key - @return {Boolean} true if an item was removed, false otherwise - */ - "delete": function(key) { - if (this.size === 0) { return false; } - // don't use ES6 "delete" because it will be annoying - // to use in browsers that are not ES6 friendly; - var keys = this.keys; - var values = this.values; - var guid = guidFor(key); - - if (keys["delete"](key, guid)) { - delete values[guid]; - this.size = keys.size; - return true; - } else { - return false; - } - }, - - /** - Check whether a key is present. - - @method has - @param {*} key - @return {Boolean} true if the item was present, false otherwise - */ - has: function(key) { - return this.keys.has(key); - }, - - /** - Iterate over all the keys and values. Calls the function once - for each key, passing in value, key, and the map being iterated over, - in that order. - - The keys are guaranteed to be iterated over in insertion order. - - @method forEach - @param {Function} callback - @param {*} self if passed, the `this` value inside the - callback. By default, `this` is the map. - */ - forEach: function(callback /*, thisArg*/) { - if (typeof callback !== 'function') { - missingFunction(callback); - } - - if (this.size === 0) { return; } - - var length = arguments.length; - var map = this; - var cb, thisArg; - - if (length === 2) { - thisArg = arguments[1]; - cb = function(key) { - callback.call(thisArg, map.get(key), key, map); - }; - } else { - cb = function(key) { - callback(map.get(key), key, map); - }; - } - - this.keys.forEach(cb); - }, - - /** - @method clear - */ - clear: function() { - this.keys.clear(); - this.values = create(null); - this.size = 0; - }, - - /** - @method copy - @return {Ember.Map} - */ - copy: function() { - return copyMap(this, new Map()); - } - }; - - deprecateProperty(Map.prototype, 'length', 'size'); - - /** - @class MapWithDefault - @namespace Ember - @extends Ember.Map - @private - @constructor - @param [options] - @param {*} [options.defaultValue] - */ - function MapWithDefault(options) { - this._super$constructor(); - this.defaultValue = options.defaultValue; - } - - /** - @method create - @static - @param [options] - @param {*} [options.defaultValue] - @return {Ember.MapWithDefault|Ember.Map} If options are passed, returns - `Ember.MapWithDefault` otherwise returns `Ember.Map` - */ - MapWithDefault.create = function(options) { - if (options) { - return new MapWithDefault(options); - } else { - return new Map(); - } - }; - - MapWithDefault.prototype = create(Map.prototype); - MapWithDefault.prototype.constructor = MapWithDefault; - MapWithDefault.prototype._super$constructor = Map; - MapWithDefault.prototype._super$get = Map.prototype.get; - - /** - Retrieve the value associated with a given key. - - @method get - @param {*} key - @return {*} the value associated with the key, or the default value - */ - MapWithDefault.prototype.get = function(key) { - var hasValue = this.has(key); - - if (hasValue) { - return this._super$get(key); - } else { - var defaultValue = this.defaultValue(key); - this.set(key, defaultValue); - return defaultValue; - } - }; - - /** - @method copy - @return {Ember.MapWithDefault} - */ - MapWithDefault.prototype.copy = function() { - var Constructor = this.constructor; - return copyMap(this, new Constructor({ - defaultValue: this.defaultValue - })); - }; - - __exports__["default"] = Map; - - __exports__.OrderedSet = OrderedSet; - __exports__.Map = Map; - __exports__.MapWithDefault = MapWithDefault; - }); -enifed("ember-metal/merge", - ["ember-metal/keys","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var keys = __dependency1__["default"]; - - /** - Merge the contents of two objects together into the first object. - - ```javascript - Ember.merge({first: 'Tom'}, {last: 'Dale'}); // {first: 'Tom', last: 'Dale'} - var a = {first: 'Yehuda'}, b = {last: 'Katz'}; - Ember.merge(a, b); // a == {first: 'Yehuda', last: 'Katz'}, b == {last: 'Katz'} - ``` - - @method merge - @for Ember - @param {Object} original The object to merge into - @param {Object} updates The object to copy properties from - @return {Object} - */ - __exports__["default"] = function merge(original, updates) { - if (!updates || typeof updates !== 'object') { - return original; - } - - var props = keys(updates); - var prop; - var length = props.length; - - for (var i = 0; i < length; i++) { - prop = props[i]; - original[prop] = updates[prop]; - } - - return original; - } - }); -enifed("ember-metal/mixin", - ["ember-metal/core","ember-metal/merge","ember-metal/array","ember-metal/platform","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/expand_properties","ember-metal/properties","ember-metal/computed","ember-metal/binding","ember-metal/observer","ember-metal/events","ember-metal/streams/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __exports__) { - // Remove "use strict"; from transpiled module until - // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed - // - // REMOVE_USE_STRICT: true - - /** - @module ember - @submodule ember-metal - */ - - var Ember = __dependency1__["default"]; - // warn, assert, wrap, et; - var merge = __dependency2__["default"]; - var a_indexOf = __dependency3__.indexOf; - var a_forEach = __dependency3__.forEach; - var o_create = __dependency4__.create; - var get = __dependency5__.get; - var set = __dependency6__.set; - var trySet = __dependency6__.trySet; - var guidFor = __dependency7__.guidFor; - var metaFor = __dependency7__.meta; - var wrap = __dependency7__.wrap; - var makeArray = __dependency7__.makeArray; - var isArray = __dependency7__.isArray; - var expandProperties = __dependency8__["default"]; - var Descriptor = __dependency9__.Descriptor; - var defineProperty = __dependency9__.defineProperty; - var ComputedProperty = __dependency10__.ComputedProperty; - var Binding = __dependency11__.Binding; - var addObserver = __dependency12__.addObserver; - var removeObserver = __dependency12__.removeObserver; - var addBeforeObserver = __dependency12__.addBeforeObserver; - var removeBeforeObserver = __dependency12__.removeBeforeObserver; - var _suspendObserver = __dependency12__._suspendObserver; - var addListener = __dependency13__.addListener; - var removeListener = __dependency13__.removeListener; - var isStream = __dependency14__.isStream; - - var REQUIRED; - var a_slice = [].slice; - - function superFunction(){ - var func = this.__nextSuper; - var ret; - - if (func) { - var length = arguments.length; - this.__nextSuper = null; - if (length === 0) { - ret = func.call(this); - } else if (length === 1) { - ret = func.call(this, arguments[0]); - } else if (length === 2) { - ret = func.call(this, arguments[0], arguments[1]); - } else { - ret = func.apply(this, arguments); - } - this.__nextSuper = func; - return ret; - } - } - - // ensure we prime superFunction to mitigate - // v8 bug potentially incorrectly deopts this function: https://code.google.com/p/v8/issues/detail?id=3709 - var primer = { - __nextSuper: function(a,b,c,d ) { } - }; - - superFunction.call(primer); - superFunction.call(primer, 1); - superFunction.call(primer, 1, 2); - superFunction.call(primer, 1, 2, 3); - - function mixinsMeta(obj) { - var m = metaFor(obj, true); - var ret = m.mixins; - if (!ret) { - ret = m.mixins = {}; - } else if (!m.hasOwnProperty('mixins')) { - ret = m.mixins = o_create(ret); - } - return ret; - } - - function isMethod(obj) { - return 'function' === typeof obj && - obj.isMethod !== false && - obj !== Boolean && - obj !== Object && - obj !== Number && - obj !== Array && - obj !== Date && - obj !== String; - } - - var CONTINUE = {}; - - function mixinProperties(mixinsMeta, mixin) { - var guid; - - if (mixin instanceof Mixin) { - guid = guidFor(mixin); - if (mixinsMeta[guid]) { return CONTINUE; } - mixinsMeta[guid] = mixin; - return mixin.properties; - } else { - return mixin; // apply anonymous mixin properties - } - } - - function concatenatedMixinProperties(concatProp, props, values, base) { - var concats; - - // reset before adding each new mixin to pickup concats from previous - concats = values[concatProp] || base[concatProp]; - if (props[concatProp]) { - concats = concats ? concats.concat(props[concatProp]) : props[concatProp]; - } - - return concats; - } - - function giveDescriptorSuper(meta, key, property, values, descs) { - var superProperty; - - // Computed properties override methods, and do not call super to them - if (values[key] === undefined) { - // Find the original descriptor in a parent mixin - superProperty = descs[key]; - } - - // If we didn't find the original descriptor in a parent mixin, find - // it on the original object. - superProperty = superProperty || meta.descs[key]; - - if (superProperty === undefined || !(superProperty instanceof ComputedProperty)) { - return property; - } - - // Since multiple mixins may inherit from the same parent, we need - // to clone the computed property so that other mixins do not receive - // the wrapped version. - property = o_create(property); - property.func = wrap(property.func, superProperty.func); - - return property; - } - - var sourceAvailable = (function() { - return this; - }).toString().indexOf('return this;') > -1; - - function giveMethodSuper(obj, key, method, values, descs) { - var superMethod; - - // Methods overwrite computed properties, and do not call super to them. - if (descs[key] === undefined) { - // Find the original method in a parent mixin - superMethod = values[key]; - } - - // If we didn't find the original value in a parent mixin, find it in - // the original object - superMethod = superMethod || obj[key]; - - // Only wrap the new method if the original method was a function - if (superMethod === undefined || 'function' !== typeof superMethod) { - return method; - } - - var hasSuper; - if (sourceAvailable) { - hasSuper = method.__hasSuper; - - if (hasSuper === undefined) { - hasSuper = method.toString().indexOf('_super') > -1; - method.__hasSuper = hasSuper; - } - } - - if (sourceAvailable === false || hasSuper) { - return wrap(method, superMethod); - } else { - return method; - } - } - - function applyConcatenatedProperties(obj, key, value, values) { - var baseValue = values[key] || obj[key]; - - if (baseValue) { - if ('function' === typeof baseValue.concat) { - if (value === null || value === undefined) { - return baseValue; - } else { - return baseValue.concat(value); - } - } else { - return makeArray(baseValue).concat(value); - } - } else { - return makeArray(value); - } - } - - function applyMergedProperties(obj, key, value, values) { - var baseValue = values[key] || obj[key]; - - Ember.assert("You passed in `" + JSON.stringify(value) + "` as the value for `" + key + - "` but `" + key + "` cannot be an Array", !isArray(value)); - - if (!baseValue) { return value; } - - var newBase = merge({}, baseValue); - var hasFunction = false; - - for (var prop in value) { - if (!value.hasOwnProperty(prop)) { continue; } - - var propValue = value[prop]; - if (isMethod(propValue)) { - // TODO: support for Computed Properties, etc? - hasFunction = true; - newBase[prop] = giveMethodSuper(obj, prop, propValue, baseValue, {}); - } else { - newBase[prop] = propValue; - } - } - - if (hasFunction) { - newBase._super = superFunction; - } - - return newBase; - } - - function addNormalizedProperty(base, key, value, meta, descs, values, concats, mergings) { - if (value instanceof Descriptor) { - if (value === REQUIRED && descs[key]) { return CONTINUE; } - - // Wrap descriptor function to implement - // __nextSuper() if needed - if (value.func) { - value = giveDescriptorSuper(meta, key, value, values, descs); - } - - descs[key] = value; - values[key] = undefined; - } else { - if ((concats && a_indexOf.call(concats, key) >= 0) || - key === 'concatenatedProperties' || - key === 'mergedProperties') { - value = applyConcatenatedProperties(base, key, value, values); - } else if ((mergings && a_indexOf.call(mergings, key) >= 0)) { - value = applyMergedProperties(base, key, value, values); - } else if (isMethod(value)) { - value = giveMethodSuper(base, key, value, values, descs); - } - - descs[key] = undefined; - values[key] = value; - } - } - - function mergeMixins(mixins, m, descs, values, base, keys) { - var mixin, props, key, concats, mergings, meta; - - function removeKeys(keyName) { - delete descs[keyName]; - delete values[keyName]; - } - - for(var i=0, l=mixins.length; i 0) { - var m = new Array(length); - - for (var i = 0; i < length; i++) { - var x = args[i]; - if (x instanceof Mixin) { - m[i] = x; - } else { - m[i] = new Mixin(undefined, x); - } - } - - this.mixins = m; - } else { - this.mixins = undefined; - } - this.ownerConstructor = undefined; - } - - Mixin._apply = applyMixin; - - Mixin.applyPartial = function(obj) { - var args = a_slice.call(arguments, 1); - return applyMixin(obj, args, true); - }; - - Mixin.finishPartial = finishPartial; - - // ES6TODO: this relies on a global state? - Ember.anyUnprocessedMixins = false; - - /** - @method create - @static - @param arguments* - */ - Mixin.create = function() { - // ES6TODO: this relies on a global state? - Ember.anyUnprocessedMixins = true; - var M = this; - var length = arguments.length; - var args = new Array(length); - for (var i = 0; i < length; i++) { - args[i] = arguments[i]; - } - return new M(args, undefined); - }; - - var MixinPrototype = Mixin.prototype; - - /** - @method reopen - @param arguments* - */ - MixinPrototype.reopen = function() { - var mixin; - - if (this.properties) { - mixin = new Mixin(undefined, this.properties); - this.properties = undefined; - this.mixins = [mixin]; - } else if (!this.mixins) { - this.mixins = []; - } - - var len = arguments.length; - var mixins = this.mixins; - var idx; - - for(idx=0; idx < len; idx++) { - mixin = arguments[idx]; - Ember.assert('Expected hash or Mixin instance, got ' + Object.prototype.toString.call(mixin), - typeof mixin === 'object' && mixin !== null && - Object.prototype.toString.call(mixin) !== '[object Array]'); - - if (mixin instanceof Mixin) { - mixins.push(mixin); - } else { - mixins.push(new Mixin(undefined, mixin)); - } - } - - return this; - }; - - /** - @method apply - @param obj - @return applied object - */ - MixinPrototype.apply = function(obj) { - return applyMixin(obj, [this], false); - }; - - MixinPrototype.applyPartial = function(obj) { - return applyMixin(obj, [this], true); - }; - - function _detect(curMixin, targetMixin, seen) { - var guid = guidFor(curMixin); - - if (seen[guid]) { return false; } - seen[guid] = true; - - if (curMixin === targetMixin) { return true; } - var mixins = curMixin.mixins; - var loc = mixins ? mixins.length : 0; - while (--loc >= 0) { - if (_detect(mixins[loc], targetMixin, seen)) { return true; } - } - return false; - } - - /** - @method detect - @param obj - @return {Boolean} - */ - MixinPrototype.detect = function(obj) { - if (!obj) { return false; } - if (obj instanceof Mixin) { return _detect(obj, this, {}); } - var m = obj['__ember_meta__']; - var mixins = m && m.mixins; - if (mixins) { - return !!mixins[guidFor(this)]; - } - return false; - }; - - MixinPrototype.without = function() { - var ret = new Mixin([this]); - ret._without = a_slice.call(arguments); - return ret; - }; - - function _keys(ret, mixin, seen) { - if (seen[guidFor(mixin)]) { return; } - seen[guidFor(mixin)] = true; - - if (mixin.properties) { - var props = mixin.properties; - for (var key in props) { - if (props.hasOwnProperty(key)) { ret[key] = true; } - } - } else if (mixin.mixins) { - a_forEach.call(mixin.mixins, function(x) { _keys(ret, x, seen); }); - } - } - - MixinPrototype.keys = function() { - var keys = {}; - var seen = {}; - var ret = []; - _keys(keys, this, seen); - for(var key in keys) { - if (keys.hasOwnProperty(key)) { - ret.push(key); - } - } - return ret; - }; - - // returns the mixins currently applied to the specified object - // TODO: Make Ember.mixin - Mixin.mixins = function(obj) { - var m = obj['__ember_meta__']; - var mixins = m && m.mixins; - var ret = []; - - if (!mixins) { return ret; } - - for (var key in mixins) { - var mixin = mixins[key]; - - // skip primitive mixins since these are always anonymous - if (!mixin.properties) { ret.push(mixin); } - } - - return ret; - }; - - REQUIRED = new Descriptor(); - REQUIRED.toString = function() { return '(Required Property)'; }; - - /** - Denotes a required property for a mixin - - @method required - @for Ember - */ - function required() { - return REQUIRED; - } - - __exports__.required = required;function Alias(methodName) { - this.methodName = methodName; - } - - Alias.prototype = new Descriptor(); - - /** - Makes a method available via an additional name. - - ```javascript - App.Person = Ember.Object.extend({ - name: function() { - return 'Tomhuda Katzdale'; - }, - moniker: Ember.aliasMethod('name') - }); - - var goodGuy = App.Person.create(); - - goodGuy.name(); // 'Tomhuda Katzdale' - goodGuy.moniker(); // 'Tomhuda Katzdale' - ``` - - @method aliasMethod - @for Ember - @param {String} methodName name of the method to alias - @return {Ember.Descriptor} - */ - function aliasMethod(methodName) { - return new Alias(methodName); - } - - __exports__.aliasMethod = aliasMethod;// .......................................................... - // OBSERVER HELPER - // - - /** - Specify a method that observes property changes. - - ```javascript - Ember.Object.extend({ - valueObserver: Ember.observer('value', function() { - // Executes whenever the "value" property changes - }) - }); - ``` - - In the future this method may become asynchronous. If you want to ensure - synchronous behavior, use `immediateObserver`. - - Also available as `Function.prototype.observes` if prototype extensions are - enabled. - - @method observer - @for Ember - @param {String} propertyNames* - @param {Function} func - @return func - */ - function observer() { - var func = a_slice.call(arguments, -1)[0]; - var paths; - - var addWatchedProperty = function (path) { paths.push(path); }; - var _paths = a_slice.call(arguments, 0, -1); - - if (typeof func !== "function") { - // revert to old, soft-deprecated argument ordering - - func = arguments[0]; - _paths = a_slice.call(arguments, 1); - } - - paths = []; - - for (var i=0; i<_paths.length; ++i) { - expandProperties(_paths[i], addWatchedProperty); - } - - if (typeof func !== "function") { - throw new Ember.Error("Ember.observer called without a function"); - } - - func.__ember_observes__ = paths; - return func; - } - - __exports__.observer = observer;/** - Specify a method that observes property changes. - - ```javascript - Ember.Object.extend({ - valueObserver: Ember.immediateObserver('value', function() { - // Executes whenever the "value" property changes - }) - }); - ``` - - In the future, `Ember.observer` may become asynchronous. In this event, - `Ember.immediateObserver` will maintain the synchronous behavior. - - Also available as `Function.prototype.observesImmediately` if prototype extensions are - enabled. - - @method immediateObserver - @for Ember - @param {String} propertyNames* - @param {Function} func - @return func - */ - function immediateObserver() { - for (var i=0, l=arguments.length; i this.changingFrom ? 'green' : 'red'; - // logic - } - }), - - friendsDidChange: Ember.observer('friends.@each.name', function(obj, keyName) { - // some logic - // obj.get(keyName) returns friends array - }) - }); - ``` - - Also available as `Function.prototype.observesBefore` if prototype extensions are - enabled. - - @method beforeObserver - @for Ember - @param {String} propertyNames* - @param {Function} func - @return func - */ - function beforeObserver() { - var func = a_slice.call(arguments, -1)[0]; - var paths; - - var addWatchedProperty = function(path) { paths.push(path); }; - - var _paths = a_slice.call(arguments, 0, -1); - - if (typeof func !== "function") { - // revert to old, soft-deprecated argument ordering - - func = arguments[0]; - _paths = a_slice.call(arguments, 1); - } - - paths = []; - - for (var i=0; i<_paths.length; ++i) { - expandProperties(_paths[i], addWatchedProperty); - } - - if (typeof func !== "function") { - throw new Ember.Error("Ember.beforeObserver called without a function"); - } - - func.__ember_observesBefore__ = paths; - return func; - } - - __exports__.beforeObserver = beforeObserver;__exports__.IS_BINDING = IS_BINDING; - __exports__.Mixin = Mixin; - }); -enifed("ember-metal/observer", - ["ember-metal/watching","ember-metal/array","ember-metal/events","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var watch = __dependency1__.watch; - var unwatch = __dependency1__.unwatch; - var map = __dependency2__.map; - var listenersFor = __dependency3__.listenersFor; - var addListener = __dependency3__.addListener; - var removeListener = __dependency3__.removeListener; - var suspendListeners = __dependency3__.suspendListeners; - var suspendListener = __dependency3__.suspendListener; - /** - @module ember-metal - */ - - var AFTER_OBSERVERS = ':change'; - var BEFORE_OBSERVERS = ':before'; - - function changeEvent(keyName) { - return keyName + AFTER_OBSERVERS; - } - - function beforeEvent(keyName) { - return keyName + BEFORE_OBSERVERS; - } - - /** - @method addObserver - @for Ember - @param obj - @param {String} path - @param {Object|Function} targetOrMethod - @param {Function|String} [method] - */ - function addObserver(obj, _path, target, method) { - addListener(obj, changeEvent(_path), target, method); - watch(obj, _path); - - return this; - } - - __exports__.addObserver = addObserver;function observersFor(obj, path) { - return listenersFor(obj, changeEvent(path)); - } - - __exports__.observersFor = observersFor;/** - @method removeObserver - @for Ember - @param obj - @param {String} path - @param {Object|Function} target - @param {Function|String} [method] - */ - function removeObserver(obj, path, target, method) { - unwatch(obj, path); - removeListener(obj, changeEvent(path), target, method); - - return this; - } - - __exports__.removeObserver = removeObserver;/** - @method addBeforeObserver - @for Ember - @param obj - @param {String} path - @param {Object|Function} target - @param {Function|String} [method] - */ - function addBeforeObserver(obj, path, target, method) { - addListener(obj, beforeEvent(path), target, method); - watch(obj, path); - - return this; - } - - __exports__.addBeforeObserver = addBeforeObserver;// Suspend observer during callback. - // - // This should only be used by the target of the observer - // while it is setting the observed path. - function _suspendBeforeObserver(obj, path, target, method, callback) { - return suspendListener(obj, beforeEvent(path), target, method, callback); - } - - __exports__._suspendBeforeObserver = _suspendBeforeObserver;function _suspendObserver(obj, path, target, method, callback) { - return suspendListener(obj, changeEvent(path), target, method, callback); - } - - __exports__._suspendObserver = _suspendObserver;function _suspendBeforeObservers(obj, paths, target, method, callback) { - var events = map.call(paths, beforeEvent); - return suspendListeners(obj, events, target, method, callback); - } - - __exports__._suspendBeforeObservers = _suspendBeforeObservers;function _suspendObservers(obj, paths, target, method, callback) { - var events = map.call(paths, changeEvent); - return suspendListeners(obj, events, target, method, callback); - } - - __exports__._suspendObservers = _suspendObservers;function beforeObserversFor(obj, path) { - return listenersFor(obj, beforeEvent(path)); - } - - __exports__.beforeObserversFor = beforeObserversFor;/** - @method removeBeforeObserver - @for Ember - @param obj - @param {String} path - @param {Object|Function} target - @param {Function|String} [method] - */ - function removeBeforeObserver(obj, path, target, method) { - unwatch(obj, path); - removeListener(obj, beforeEvent(path), target, method); - - return this; - } - - __exports__.removeBeforeObserver = removeBeforeObserver; - }); -enifed("ember-metal/observer_set", - ["ember-metal/utils","ember-metal/events","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var guidFor = __dependency1__.guidFor; - var sendEvent = __dependency2__.sendEvent; - - /* - this.observerSet = { - [senderGuid]: { // variable name: `keySet` - [keyName]: listIndex - } - }, - this.observers = [ - { - sender: obj, - keyName: keyName, - eventName: eventName, - listeners: [ - [target, method, flags] - ] - }, - ... - ] - */ - __exports__["default"] = ObserverSet; - function ObserverSet() { - this.clear(); - } - - - ObserverSet.prototype.add = function(sender, keyName, eventName) { - var observerSet = this.observerSet; - var observers = this.observers; - var senderGuid = guidFor(sender); - var keySet = observerSet[senderGuid]; - var index; - - if (!keySet) { - observerSet[senderGuid] = keySet = {}; - } - index = keySet[keyName]; - if (index === undefined) { - index = observers.push({ - sender: sender, - keyName: keyName, - eventName: eventName, - listeners: [] - }) - 1; - keySet[keyName] = index; - } - return observers[index].listeners; - }; - - ObserverSet.prototype.flush = function() { - var observers = this.observers; - var i, len, observer, sender; - this.clear(); - for (i=0, len=observers.length; i < len; ++i) { - observer = observers[i]; - sender = observer.sender; - if (sender.isDestroying || sender.isDestroyed) { continue; } - sendEvent(sender, observer.eventName, [sender, observer.keyName], observer.listeners); - } - }; - - ObserverSet.prototype.clear = function() { - this.observerSet = {}; - this.observers = []; - }; - }); -enifed("ember-metal/path_cache", - ["ember-metal/cache","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Cache = __dependency1__["default"]; - - var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; - var IS_GLOBAL_PATH = /^([A-Z$]|([0-9][A-Z$])).*[\.]/; - var HAS_THIS = 'this.'; - - var isGlobalCache = new Cache(1000, function(key) { return IS_GLOBAL.test(key); }); - var isGlobalPathCache = new Cache(1000, function(key) { return IS_GLOBAL_PATH.test(key); }); - var hasThisCache = new Cache(1000, function(key) { return key.lastIndexOf(HAS_THIS, 0) === 0; }); - var firstDotIndexCache = new Cache(1000, function(key) { return key.indexOf('.'); }); - - var firstKeyCache = new Cache(1000, function(path) { - var index = firstDotIndexCache.get(path); - if (index === -1) { - return path; - } else { - return path.slice(0, index); - } - }); - - var tailPathCache = new Cache(1000, function(path) { - var index = firstDotIndexCache.get(path); - if (index !== -1) { - return path.slice(index + 1); - } - }); - - var caches = { - isGlobalCache: isGlobalCache, - isGlobalPathCache: isGlobalPathCache, - hasThisCache: hasThisCache, - firstDotIndexCache: firstDotIndexCache, - firstKeyCache: firstKeyCache, - tailPathCache: tailPathCache - }; - __exports__.caches = caches; - function isGlobal(path) { - return isGlobalCache.get(path); - } - - __exports__.isGlobal = isGlobal;function isGlobalPath(path) { - return isGlobalPathCache.get(path); - } - - __exports__.isGlobalPath = isGlobalPath;function hasThis(path) { - return hasThisCache.get(path); - } - - __exports__.hasThis = hasThis;function isPath(path) { - return firstDotIndexCache.get(path) !== -1; - } - - __exports__.isPath = isPath;function getFirstKey(path) { - return firstKeyCache.get(path); - } - - __exports__.getFirstKey = getFirstKey;function getTailPath(path) { - return tailPathCache.get(path); - } - - __exports__.getTailPath = getTailPath; - }); -enifed("ember-metal/platform", - ["ember-metal/platform/define_property","ember-metal/platform/define_properties","ember-metal/platform/create","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var hasES5CompliantDefineProperty = __dependency1__.hasES5CompliantDefineProperty; - var defineProperty = __dependency1__.defineProperty; - var defineProperties = __dependency2__["default"]; - var create = __dependency3__["default"]; - - /** - @module ember-metal - */ - - var hasPropertyAccessors = hasES5CompliantDefineProperty; - var canDefineNonEnumerableProperties = hasES5CompliantDefineProperty; - - /** - Platform specific methods and feature detectors needed by the framework. - - @class platform - @namespace Ember - @static - */ - - __exports__.create = create; - __exports__.defineProperty = defineProperty; - __exports__.defineProperties = defineProperties; - __exports__.hasPropertyAccessors = hasPropertyAccessors; - __exports__.canDefineNonEnumerableProperties = canDefineNonEnumerableProperties; - }); -enifed("ember-metal/platform/create", - ["ember-metal/platform/define_properties","exports"], - function(__dependency1__, __exports__) { - // Remove "use strict"; from transpiled module until - // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed - // - // REMOVE_USE_STRICT: true - // - - var defineProperties = __dependency1__["default"]; - - /** - @class platform - @namespace Ember - @static - */ - - /** - Identical to `Object.create()`. Implements if not available natively. - - @since 1.8.0 - @method create - @for Ember - */ - var create; - // ES5 15.2.3.5 - // http://es5.github.com/#x15.2.3.5 - if (!(Object.create && !Object.create(null).hasOwnProperty)) { - /* jshint scripturl:true, proto:true */ - // Contributed by Brandon Benvie, October, 2012 - var createEmpty; - var supportsProto = !({'__proto__':null} instanceof Object); - // the following produces false positives - // in Opera Mini => not a reliable check - // Object.prototype.__proto__ === null - if (supportsProto || typeof document === 'undefined') { - createEmpty = function () { - return { "__proto__": null }; - }; - } else { - // In old IE __proto__ can't be used to manually set `null`, nor does - // any other method exist to make an object that inherits from nothing, - // aside from Object.prototype itself. Instead, create a new global - // object and *steal* its Object.prototype and strip it bare. This is - // used as the prototype to create nullary objects. - createEmpty = function () { - var iframe = document.createElement('iframe'); - var parent = document.body || document.documentElement; - iframe.style.display = 'none'; - parent.appendChild(iframe); - iframe.src = 'javascript:'; - var empty = iframe.contentWindow.Object.prototype; - parent.removeChild(iframe); - iframe = null; - delete empty.constructor; - delete empty.hasOwnProperty; - delete empty.propertyIsEnumerable; - delete empty.isPrototypeOf; - delete empty.toLocaleString; - delete empty.toString; - delete empty.valueOf; - - function Empty() {} - Empty.prototype = empty; - // short-circuit future calls - createEmpty = function () { - return new Empty(); - }; - return new Empty(); - }; - } - - create = Object.create = function create(prototype, properties) { - - var object; - function Type() {} // An empty constructor. - - if (prototype === null) { - object = createEmpty(); - } else { - if (typeof prototype !== "object" && typeof prototype !== "function") { - // In the native implementation `parent` can be `null` - // OR *any* `instanceof Object` (Object|Function|Array|RegExp|etc) - // Use `typeof` tho, b/c in old IE, DOM elements are not `instanceof Object` - // like they are in modern browsers. Using `Object.create` on DOM elements - // is...err...probably inappropriate, but the native version allows for it. - throw new TypeError("Object prototype may only be an Object or null"); // same msg as Chrome - } - - Type.prototype = prototype; - - object = new Type(); - } - - if (properties !== undefined) { - defineProperties(object, properties); - } - - return object; - }; - } else { - create = Object.create; - } - - __exports__["default"] = create; - }); -enifed("ember-metal/platform/define_properties", - ["ember-metal/platform/define_property","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var defineProperty = __dependency1__.defineProperty; - - var defineProperties = Object.defineProperties; - - // ES5 15.2.3.7 - // http://es5.github.com/#x15.2.3.7 - if (!defineProperties) { - defineProperties = function defineProperties(object, properties) { - for (var property in properties) { - if (properties.hasOwnProperty(property) && property !== "__proto__") { - defineProperty(object, property, properties[property]); - } - } - return object; - }; - - Object.defineProperties = defineProperties; - } - - __exports__["default"] = defineProperties; - }); -enifed("ember-metal/platform/define_property", - ["exports"], - function(__exports__) { - "use strict"; - /*globals Node */ - - /** - @class platform - @namespace Ember - @static - */ - - /** - Set to true if the platform supports native getters and setters. - - @property hasPropertyAccessors - @final - */ - - /** - Identical to `Object.defineProperty()`. Implements as much functionality - as possible if not available natively. - - @method defineProperty - @param {Object} obj The object to modify - @param {String} keyName property name to modify - @param {Object} desc descriptor hash - @return {void} - */ - var defineProperty = (function checkCompliance(defineProperty) { - if (!defineProperty) return; - try { - var a = 5; - var obj = {}; - defineProperty(obj, 'a', { - configurable: true, - enumerable: true, - get: function () { - return a; - }, - set: function (v) { - a = v; - } - }); - if (obj.a !== 5) return; - obj.a = 10; - if (a !== 10) return; - - // check non-enumerability - defineProperty(obj, 'a', { - configurable: true, - enumerable: false, - writable: true, - value: true - }); - for (var key in obj) { - if (key === 'a') return; - } - - // Detects a bug in Android <3.2 where you cannot redefine a property using - // Object.defineProperty once accessors have already been set. - if (obj.a !== true) return; - - // Detects a bug in Android <3 where redefining a property without a value changes the value - // Object.defineProperty once accessors have already been set. - defineProperty(obj, 'a', { - enumerable: false - }); - if (obj.a !== true) return; - - // defineProperty is compliant - return defineProperty; - } catch (e) { - // IE8 defines Object.defineProperty but calling it on an Object throws - return; - } - })(Object.defineProperty); - - var hasES5CompliantDefineProperty = !!defineProperty; - - if (hasES5CompliantDefineProperty && typeof document !== 'undefined') { - // This is for Safari 5.0, which supports Object.defineProperty, but not - // on DOM nodes. - var canDefinePropertyOnDOM = (function() { - try { - defineProperty(document.createElement('div'), 'definePropertyOnDOM', {}); - return true; - } catch(e) { } - - return false; - })(); - - if (!canDefinePropertyOnDOM) { - defineProperty = function(obj, keyName, desc) { - var isNode; - - if (typeof Node === "object") { - isNode = obj instanceof Node; - } else { - isNode = typeof obj === "object" && typeof obj.nodeType === "number" && typeof obj.nodeName === "string"; - } - - if (isNode) { - // TODO: Should we have a warning here? - return (obj[keyName] = desc.value); - } else { - return Object.defineProperty(obj, keyName, desc); - } - }; - } - } - - if (!hasES5CompliantDefineProperty) { - defineProperty = function defineProperty(obj, keyName, desc) { - if (!desc.get) { obj[keyName] = desc.value; } - }; - } - - __exports__.hasES5CompliantDefineProperty = hasES5CompliantDefineProperty; - __exports__.defineProperty = defineProperty; - }); -enifed("ember-metal/properties", - ["ember-metal/core","ember-metal/utils","ember-metal/platform","ember-metal/property_events","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember-metal - */ - - var Ember = __dependency1__["default"]; - var metaFor = __dependency2__.meta; - var objectDefineProperty = __dependency3__.defineProperty; - var hasPropertyAccessors = __dependency3__.hasPropertyAccessors; - var overrideChains = __dependency4__.overrideChains; - // .......................................................... - // DESCRIPTOR - // - - /** - Objects of this type can implement an interface to respond to requests to - get and set. The default implementation handles simple properties. - - You generally won't need to create or subclass this directly. - - @class Descriptor - @namespace Ember - @private - @constructor - */ - function Descriptor() {} - - __exports__.Descriptor = Descriptor;// .......................................................... - // DEFINING PROPERTIES API - // - - function MANDATORY_SETTER_FUNCTION(name) { - return function SETTER_FUNCTION(value) { - Ember.assert("You must use Ember.set() to set the `" + name + "` property (of " + this + ") to `" + value + "`.", false); - }; - } - - __exports__.MANDATORY_SETTER_FUNCTION = MANDATORY_SETTER_FUNCTION;function DEFAULT_GETTER_FUNCTION(name) { - return function GETTER_FUNCTION() { - var meta = this['__ember_meta__']; - return meta && meta.values[name]; - }; - } - - __exports__.DEFAULT_GETTER_FUNCTION = DEFAULT_GETTER_FUNCTION;/** - NOTE: This is a low-level method used by other parts of the API. You almost - never want to call this method directly. Instead you should use - `Ember.mixin()` to define new properties. - - Defines a property on an object. This method works much like the ES5 - `Object.defineProperty()` method except that it can also accept computed - properties and other special descriptors. - - Normally this method takes only three parameters. However if you pass an - instance of `Ember.Descriptor` as the third param then you can pass an - optional value as the fourth parameter. This is often more efficient than - creating new descriptor hashes for each property. - - ## Examples - - ```javascript - // ES5 compatible mode - Ember.defineProperty(contact, 'firstName', { - writable: true, - configurable: false, - enumerable: true, - value: 'Charles' - }); - - // define a simple property - Ember.defineProperty(contact, 'lastName', undefined, 'Jolley'); - - // define a computed property - Ember.defineProperty(contact, 'fullName', Ember.computed(function() { - return this.firstName+' '+this.lastName; - }).property('firstName', 'lastName')); - ``` - - @private - @method defineProperty - @for Ember - @param {Object} obj the object to define this property on. This may be a prototype. - @param {String} keyName the name of the property - @param {Ember.Descriptor} [desc] an instance of `Ember.Descriptor` (typically a - computed property) or an ES5 descriptor. - You must provide this or `data` but not both. - @param {*} [data] something other than a descriptor, that will - become the explicit value of this property. - */ - function defineProperty(obj, keyName, desc, data, meta) { - var descs, existingDesc, watching, value; - - if (!meta) meta = metaFor(obj); - descs = meta.descs; - existingDesc = meta.descs[keyName]; - var watchEntry = meta.watching[keyName]; - - watching = watchEntry !== undefined && watchEntry > 0; - - if (existingDesc instanceof Descriptor) { - existingDesc.teardown(obj, keyName); - } - - if (desc instanceof Descriptor) { - value = desc; - - descs[keyName] = desc; - - if (watching && hasPropertyAccessors) { - objectDefineProperty(obj, keyName, { - configurable: true, - enumerable: true, - writable: true, - value: undefined // make enumerable - }); - } else { - obj[keyName] = undefined; // make enumerable - } - if (desc.setup) { desc.setup(obj, keyName); } - } else { - descs[keyName] = undefined; // shadow descriptor in proto - if (desc == null) { - value = data; - - - if (watching && hasPropertyAccessors) { - meta.values[keyName] = data; - objectDefineProperty(obj, keyName, { - configurable: true, - enumerable: true, - set: MANDATORY_SETTER_FUNCTION(keyName), - get: DEFAULT_GETTER_FUNCTION(keyName) - }); - } else { - obj[keyName] = data; - } - } else { - value = desc; - - // compatibility with ES5 - objectDefineProperty(obj, keyName, desc); - } - } - - // if key is being watched, override chains that - // were initialized with the prototype - if (watching) { overrideChains(obj, keyName, meta); } - - // The `value` passed to the `didDefineProperty` hook is - // either the descriptor or data, whichever was passed. - if (obj.didDefineProperty) { obj.didDefineProperty(obj, keyName, value); } - - return this; - } - - __exports__.defineProperty = defineProperty; - }); -enifed("ember-metal/property_events", - ["ember-metal/utils","ember-metal/events","ember-metal/observer_set","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var guidFor = __dependency1__.guidFor; - var tryFinally = __dependency1__.tryFinally; - var sendEvent = __dependency2__.sendEvent; - var accumulateListeners = __dependency2__.accumulateListeners; - var ObserverSet = __dependency3__["default"]; - - var beforeObserverSet = new ObserverSet(); - var observerSet = new ObserverSet(); - var deferred = 0; - - // .......................................................... - // PROPERTY CHANGES - // - - /** - This function is called just before an object property is about to change. - It will notify any before observers and prepare caches among other things. - - Normally you will not need to call this method directly but if for some - reason you can't directly watch a property you can invoke this method - manually along with `Ember.propertyDidChange()` which you should call just - after the property value changes. - - @method propertyWillChange - @for Ember - @param {Object} obj The object with the property that will change - @param {String} keyName The property key (or path) that will change. - @return {void} - */ - function propertyWillChange(obj, keyName) { - var m = obj['__ember_meta__']; - var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; - var proto = m && m.proto; - var desc = m && m.descs[keyName]; - - if (!watching) { - return; - } - - if (proto === obj) { - return; - } - - if (desc && desc.willChange) { - desc.willChange(obj, keyName); - } - - dependentKeysWillChange(obj, keyName, m); - chainsWillChange(obj, keyName, m); - notifyBeforeObservers(obj, keyName); - } - - /** - This function is called just after an object property has changed. - It will notify any observers and clear caches among other things. - - Normally you will not need to call this method directly but if for some - reason you can't directly watch a property you can invoke this method - manually along with `Ember.propertyWillChange()` which you should call just - before the property value changes. - - @method propertyDidChange - @for Ember - @param {Object} obj The object with the property that will change - @param {String} keyName The property key (or path) that will change. - @return {void} - */ - function propertyDidChange(obj, keyName) { - var m = obj['__ember_meta__']; - var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; - var proto = m && m.proto; - var desc = m && m.descs[keyName]; - - if (proto === obj) { - return; - } - - // shouldn't this mean that we're watching this key? - if (desc && desc.didChange) { - desc.didChange(obj, keyName); - } - - if (!watching && keyName !== 'length') { - return; - } - - if (m && m.deps && m.deps[keyName]) { - dependentKeysDidChange(obj, keyName, m); - } - - chainsDidChange(obj, keyName, m, false); - notifyObservers(obj, keyName); - } - - var WILL_SEEN, DID_SEEN; - // called whenever a property is about to change to clear the cache of any dependent keys (and notify those properties of changes, etc...) - function dependentKeysWillChange(obj, depKey, meta) { - if (obj.isDestroying) { return; } - - var deps; - if (meta && meta.deps && (deps = meta.deps[depKey])) { - var seen = WILL_SEEN; - var top = !seen; - - if (top) { - seen = WILL_SEEN = {}; - } - - iterDeps(propertyWillChange, obj, deps, depKey, seen, meta); - - if (top) { - WILL_SEEN = null; - } - } - } - - // called whenever a property has just changed to update dependent keys - function dependentKeysDidChange(obj, depKey, meta) { - if (obj.isDestroying) { return; } - - var deps; - if (meta && meta.deps && (deps = meta.deps[depKey])) { - var seen = DID_SEEN; - var top = !seen; - - if (top) { - seen = DID_SEEN = {}; - } - - iterDeps(propertyDidChange, obj, deps, depKey, seen, meta); - - if (top) { - DID_SEEN = null; - } - } - } - - function keysOf(obj) { - var keys = []; - - for (var key in obj) { - keys.push(key); - } - - return keys; - } - - function iterDeps(method, obj, deps, depKey, seen, meta) { - var keys, key, i, desc; - var guid = guidFor(obj); - var current = seen[guid]; - - if (!current) { - current = seen[guid] = {}; - } - - if (current[depKey]) { - return; - } - - current[depKey] = true; - - if (deps) { - keys = keysOf(deps); - var descs = meta.descs; - for (i=0; i 0) { - ret = meta.values[keyName]; - } else { - ret = obj[keyName]; - } - - if (ret === undefined && - 'object' === typeof obj && !(keyName in obj) && 'function' === typeof obj.unknownProperty) { - return obj.unknownProperty(keyName); - } - - return ret; - } - }; - - /** - Normalizes a target/path pair to reflect that actual target/path that should - be observed, etc. This takes into account passing in global property - paths (i.e. a path beginning with a capital letter not defined on the - target). - - @private - @method normalizeTuple - @for Ember - @param {Object} target The current target. May be `null`. - @param {String} path A path on the target or a global property path. - @return {Array} a temporary array with the normalized target/path pair. - */ - function normalizeTuple(target, path) { - var hasThis = pathHasThis(path); - var isGlobal = !hasThis && isGlobalPath(path); - var key; - - if (!target || isGlobal) target = Ember.lookup; - if (hasThis) path = path.slice(5); - - Ember.deprecate( - "normalizeTuple will return '"+path+"' as a non-global. This behavior will change in the future (issue #3852)", - target === Ember.lookup || !target || hasThis || isGlobal || !isGlobalPath(path+'.') - ); - - if (target === Ember.lookup) { - key = path.match(FIRST_KEY)[0]; - target = get(target, key); - path = path.slice(key.length+1); - } - - // must return some kind of path to be valid else other things will break. - if (!path || path.length===0) throw new EmberError('Path cannot be empty'); - - return [ target, path ]; - } - - function _getPath(root, path) { - var hasThis, parts, tuple, idx, len; - - // If there is no root and path is a key name, return that - // property from the global object. - // E.g. get('Ember') -> Ember - if (root === null && !isPath(path)) { - return get(Ember.lookup, path); - } - - // detect complicated paths and normalize them - hasThis = pathHasThis(path); - - if (!root || hasThis) { - tuple = normalizeTuple(root, path); - root = tuple[0]; - path = tuple[1]; - tuple.length = 0; - } - - parts = path.split("."); - len = parts.length; - for (idx = 0; root != null && idx < len; idx++) { - root = get(root, parts[idx], true); - if (root && root.isDestroyed) { return undefined; } - } - return root; - } - - function getWithDefault(root, key, defaultValue) { - var value = get(root, key); - - if (value === undefined) { return defaultValue; } - return value; - } - - __exports__.getWithDefault = getWithDefault;__exports__["default"] = get; - __exports__.get = get; - __exports__.normalizeTuple = normalizeTuple; - __exports__._getPath = _getPath; - }); -enifed("ember-metal/property_set", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_events","ember-metal/properties","ember-metal/error","ember-metal/path_cache","ember-metal/platform","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var getPath = __dependency2__._getPath; - var propertyWillChange = __dependency3__.propertyWillChange; - var propertyDidChange = __dependency3__.propertyDidChange; - var defineProperty = __dependency4__.defineProperty; - var EmberError = __dependency5__["default"]; - var isPath = __dependency6__.isPath; - var hasPropertyAccessors = __dependency7__.hasPropertyAccessors; - - var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; - - /** - Sets the value of a property on an object, respecting computed properties - and notifying observers and other listeners of the change. If the - property is not defined but the object implements the `setUnknownProperty` - method then that will be invoked as well. - - @method set - @for Ember - @param {Object} obj The object to modify. - @param {String} keyName The property key to set - @param {Object} value The value to set - @return {Object} the passed value. - */ - var set = function set(obj, keyName, value, tolerant) { - if (typeof obj === 'string') { - Ember.assert("Path '" + obj + "' must be global if no obj is given.", IS_GLOBAL.test(obj)); - value = keyName; - keyName = obj; - obj = null; - } - - Ember.assert("Cannot call set with "+ keyName +" key.", !!keyName); - - if (!obj) { - return setPath(obj, keyName, value, tolerant); - } - - var meta = obj['__ember_meta__']; - var desc = meta && meta.descs[keyName]; - var isUnknown, currentValue; - - if (desc === undefined && isPath(keyName)) { - return setPath(obj, keyName, value, tolerant); - } - - Ember.assert("You need to provide an object and key to `set`.", !!obj && keyName !== undefined); - Ember.assert('calling set on destroyed object', !obj.isDestroyed); - - if (desc !== undefined) { - desc.set(obj, keyName, value); - } else { - - if (typeof obj === 'object' && obj !== null && value !== undefined && obj[keyName] === value) { - return value; - } - - isUnknown = 'object' === typeof obj && !(keyName in obj); - - // setUnknownProperty is called if `obj` is an object, - // the property does not already exist, and the - // `setUnknownProperty` method exists on the object - if (isUnknown && 'function' === typeof obj.setUnknownProperty) { - obj.setUnknownProperty(keyName, value); - } else if (meta && meta.watching[keyName] > 0) { - if (meta.proto !== obj) { - - if (hasPropertyAccessors) { - currentValue = meta.values[keyName]; - } else { - currentValue = obj[keyName]; - } - } - // only trigger a change if the value has changed - if (value !== currentValue) { - propertyWillChange(obj, keyName); - - if (hasPropertyAccessors) { - if ( - (currentValue === undefined && !(keyName in obj)) || - !Object.prototype.propertyIsEnumerable.call(obj, keyName) - ) { - defineProperty(obj, keyName, null, value); // setup mandatory setter - } else { - meta.values[keyName] = value; - } - } else { - obj[keyName] = value; - } - propertyDidChange(obj, keyName); - } - } else { - obj[keyName] = value; - } - } - return value; - }; - - function setPath(root, path, value, tolerant) { - var keyName; - - // get the last part of the path - keyName = path.slice(path.lastIndexOf('.') + 1); - - // get the first part of the part - path = (path === keyName) ? keyName : path.slice(0, path.length-(keyName.length+1)); - - // unless the path is this, look up the first part to - // get the root - if (path !== 'this') { - root = getPath(root, path); - } - - if (!keyName || keyName.length === 0) { - throw new EmberError('Property set failed: You passed an empty path'); - } - - if (!root) { - if (tolerant) { return; } - else { throw new EmberError('Property set failed: object in path "'+path+'" could not be found or was destroyed.'); } - } - - return set(root, keyName, value); - } - - /** - Error-tolerant form of `Ember.set`. Will not blow up if any part of the - chain is `undefined`, `null`, or destroyed. - - This is primarily used when syncing bindings, which may try to update after - an object has been destroyed. - - @method trySet - @for Ember - @param {Object} obj The object to modify. - @param {String} path The property path to set - @param {Object} value The value to set - */ - function trySet(root, path, value) { - return set(root, path, value, true); - } - - __exports__.trySet = trySet;__exports__.set = set; - }); -enifed("ember-metal/run_loop", - ["ember-metal/core","ember-metal/utils","ember-metal/array","ember-metal/property_events","backburner","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var apply = __dependency2__.apply; - var GUID_KEY = __dependency2__.GUID_KEY; - var indexOf = __dependency3__.indexOf; - var beginPropertyChanges = __dependency4__.beginPropertyChanges; - var endPropertyChanges = __dependency4__.endPropertyChanges; - var Backburner = __dependency5__["default"]; - - function onBegin(current) { - run.currentRunLoop = current; - } - - function onEnd(current, next) { - run.currentRunLoop = next; - } - - // ES6TODO: should Backburner become es6? - var backburner = new Backburner(['sync', 'actions', 'destroy'], { - GUID_KEY: GUID_KEY, - sync: { - before: beginPropertyChanges, - after: endPropertyChanges - }, - defaultQueue: 'actions', - onBegin: onBegin, - onEnd: onEnd, - onErrorTarget: Ember, - onErrorMethod: 'onerror' - }); - var slice = [].slice; - - // .......................................................... - // run - this is ideally the only public API the dev sees - // - - /** - Runs the passed target and method inside of a RunLoop, ensuring any - deferred actions including bindings and views updates are flushed at the - end. - - Normally you should not need to invoke this method yourself. However if - you are implementing raw event handlers when interfacing with other - libraries or plugins, you should probably wrap all of your code inside this - call. - - ```javascript - run(function() { - // code to be executed within a RunLoop - }); - ``` - - @class run - @namespace Ember - @static - @constructor - @param {Object} [target] target of method to call - @param {Function|String} method Method to invoke. - May be a function or a string. If you pass a string - then it will be looked up on the passed target. - @param {Object} [args*] Any additional arguments you wish to pass to the method. - @return {Object} return value from invoking the passed function. - */ - __exports__["default"] = run; - function run() { - return backburner.run.apply(backburner, arguments); - } - - /** - If no run-loop is present, it creates a new one. If a run loop is - present it will queue itself to run on the existing run-loops action - queue. - - Please note: This is not for normal usage, and should be used sparingly. - - If invoked when not within a run loop: - - ```javascript - run.join(function() { - // creates a new run-loop - }); - ``` - - Alternatively, if called within an existing run loop: - - ```javascript - run(function() { - // creates a new run-loop - run.join(function() { - // joins with the existing run-loop, and queues for invocation on - // the existing run-loops action queue. - }); - }); - ``` - - @method join - @namespace Ember - @param {Object} [target] target of method to call - @param {Function|String} method Method to invoke. - May be a function or a string. If you pass a string - then it will be looked up on the passed target. - @param {Object} [args*] Any additional arguments you wish to pass to the method. - @return {Object} Return value from invoking the passed function. Please note, - when called within an existing loop, no return value is possible. - */ - run.join = function() { - return backburner.join.apply(backburner, arguments); - }; - - /** - Allows you to specify which context to call the specified function in while - adding the execution of that function to the Ember run loop. This ability - makes this method a great way to asynchronusly integrate third-party libraries - into your Ember application. - - `run.bind` takes two main arguments, the desired context and the function to - invoke in that context. Any additional arguments will be supplied as arguments - to the function that is passed in. - - Let's use the creation of a TinyMCE component as an example. Currently, - TinyMCE provides a setup configuration option we can use to do some processing - after the TinyMCE instance is initialized but before it is actually rendered. - We can use that setup option to do some additional setup for our component. - The component itself could look something like the following: - - ```javascript - App.RichTextEditorComponent = Ember.Component.extend({ - initializeTinyMCE: function(){ - tinymce.init({ - selector: '#' + this.$().prop('id'), - setup: Ember.run.bind(this, this.setupEditor) - }); - }.on('didInsertElement'), - - setupEditor: function(editor) { - this.set('editor', editor); - editor.on('change', function(){ console.log('content changed!')} ); - } - }); - ``` - - In this example, we use Ember.run.bind to bind the setupEditor message to the - context of the App.RichTextEditorComponent and to have the invocation of that - method be safely handled and excuted by the Ember run loop. - - @method bind - @namespace Ember - @param {Object} [target] target of method to call - @param {Function|String} method Method to invoke. - May be a function or a string. If you pass a string - then it will be looked up on the passed target. - @param {Object} [args*] Any additional arguments you wish to pass to the method. - @return {Function} returns a new function that will always have a particular context - @since 1.4.0 - */ - run.bind = function(target, method /* args */) { - var args = slice.call(arguments); - return function() { - return run.join.apply(run, args.concat(slice.call(arguments))); - }; - }; - - run.backburner = backburner; - run.currentRunLoop = null; - run.queues = backburner.queueNames; - - /** - Begins a new RunLoop. Any deferred actions invoked after the begin will - be buffered until you invoke a matching call to `run.end()`. This is - a lower-level way to use a RunLoop instead of using `run()`. - - ```javascript - run.begin(); - // code to be executed within a RunLoop - run.end(); - ``` - - @method begin - @return {void} - */ - run.begin = function() { - backburner.begin(); - }; - - /** - Ends a RunLoop. This must be called sometime after you call - `run.begin()` to flush any deferred actions. This is a lower-level way - to use a RunLoop instead of using `run()`. - - ```javascript - run.begin(); - // code to be executed within a RunLoop - run.end(); - ``` - - @method end - @return {void} - */ - run.end = function() { - backburner.end(); - }; - - /** - Array of named queues. This array determines the order in which queues - are flushed at the end of the RunLoop. You can define your own queues by - simply adding the queue name to this array. Normally you should not need - to inspect or modify this property. - - @property queues - @type Array - @default ['sync', 'actions', 'destroy'] - */ - - /** - Adds the passed target/method and any optional arguments to the named - queue to be executed at the end of the RunLoop. If you have not already - started a RunLoop when calling this method one will be started for you - automatically. - - At the end of a RunLoop, any methods scheduled in this way will be invoked. - Methods will be invoked in an order matching the named queues defined in - the `run.queues` property. - - ```javascript - run.schedule('sync', this, function() { - // this will be executed in the first RunLoop queue, when bindings are synced - console.log("scheduled on sync queue"); - }); - - run.schedule('actions', this, function() { - // this will be executed in the 'actions' queue, after bindings have synced. - console.log("scheduled on actions queue"); - }); - - // Note the functions will be run in order based on the run queues order. - // Output would be: - // scheduled on sync queue - // scheduled on actions queue - ``` - - @method schedule - @param {String} queue The name of the queue to schedule against. - Default queues are 'sync' and 'actions' - @param {Object} [target] target object to use as the context when invoking a method. - @param {String|Function} method The method to invoke. If you pass a string it - will be resolved on the target object at the time the scheduled item is - invoked allowing you to change the target function. - @param {Object} [arguments*] Optional arguments to be passed to the queued method. - @return {void} - */ - run.schedule = function(queue, target, method) { - checkAutoRun(); - backburner.schedule.apply(backburner, arguments); - }; - - // Used by global test teardown - run.hasScheduledTimers = function() { - return backburner.hasTimers(); - }; - - // Used by global test teardown - run.cancelTimers = function () { - backburner.cancelTimers(); - }; - - /** - Immediately flushes any events scheduled in the 'sync' queue. Bindings - use this queue so this method is a useful way to immediately force all - bindings in the application to sync. - - You should call this method anytime you need any changed state to propagate - throughout the app immediately without repainting the UI (which happens - in the later 'render' queue added by the `ember-views` package). - - ```javascript - run.sync(); - ``` - - @method sync - @return {void} - */ - run.sync = function() { - if (backburner.currentInstance) { - backburner.currentInstance.queues.sync.flush(); - } - }; - - /** - Invokes the passed target/method and optional arguments after a specified - period of time. The last parameter of this method must always be a number - of milliseconds. - - You should use this method whenever you need to run some action after a - period of time instead of using `setTimeout()`. This method will ensure that - items that expire during the same script execution cycle all execute - together, which is often more efficient than using a real setTimeout. - - ```javascript - run.later(myContext, function() { - // code here will execute within a RunLoop in about 500ms with this == myContext - }, 500); - ``` - - @method later - @param {Object} [target] target of method to invoke - @param {Function|String} method The method to invoke. - If you pass a string it will be resolved on the - target at the time the method is invoked. - @param {Object} [args*] Optional arguments to pass to the timeout. - @param {Number} wait Number of milliseconds to wait. - @return {Object} Timer information for use in cancelling, see `run.cancel`. - */ - run.later = function(/*target, method*/) { - return backburner.later.apply(backburner, arguments); - }; - - /** - Schedule a function to run one time during the current RunLoop. This is equivalent - to calling `scheduleOnce` with the "actions" queue. - - @method once - @param {Object} [target] The target of the method to invoke. - @param {Function|String} method The method to invoke. - If you pass a string it will be resolved on the - target at the time the method is invoked. - @param {Object} [args*] Optional arguments to pass to the timeout. - @return {Object} Timer information for use in cancelling, see `run.cancel`. - */ - run.once = function(/*target, method */) { - checkAutoRun(); - var length = arguments.length; - var args = new Array(length); - args[0] = 'actions'; - for (var i = 0; i < length; i++) { - args[i + 1] = arguments[i]; - } - return apply(backburner, backburner.scheduleOnce, args); - }; - - /** - Schedules a function to run one time in a given queue of the current RunLoop. - Calling this method with the same queue/target/method combination will have - no effect (past the initial call). - - Note that although you can pass optional arguments these will not be - considered when looking for duplicates. New arguments will replace previous - calls. - - ```javascript - run(function() { - var sayHi = function() { console.log('hi'); } - run.scheduleOnce('afterRender', myContext, sayHi); - run.scheduleOnce('afterRender', myContext, sayHi); - // sayHi will only be executed once, in the afterRender queue of the RunLoop - }); - ``` - - Also note that passing an anonymous function to `run.scheduleOnce` will - not prevent additional calls with an identical anonymous function from - scheduling the items multiple times, e.g.: - - ```javascript - function scheduleIt() { - run.scheduleOnce('actions', myContext, function() { console.log("Closure"); }); - } - scheduleIt(); - scheduleIt(); - // "Closure" will print twice, even though we're using `run.scheduleOnce`, - // because the function we pass to it is anonymous and won't match the - // previously scheduled operation. - ``` - - Available queues, and their order, can be found at `run.queues` - - @method scheduleOnce - @param {String} [queue] The name of the queue to schedule against. Default queues are 'sync' and 'actions'. - @param {Object} [target] The target of the method to invoke. - @param {Function|String} method The method to invoke. - If you pass a string it will be resolved on the - target at the time the method is invoked. - @param {Object} [args*] Optional arguments to pass to the timeout. - @return {Object} Timer information for use in cancelling, see `run.cancel`. - */ - run.scheduleOnce = function(/*queue, target, method*/) { - checkAutoRun(); - return backburner.scheduleOnce.apply(backburner, arguments); - }; - - /** - Schedules an item to run from within a separate run loop, after - control has been returned to the system. This is equivalent to calling - `run.later` with a wait time of 1ms. - - ```javascript - run.next(myContext, function() { - // code to be executed in the next run loop, - // which will be scheduled after the current one - }); - ``` - - Multiple operations scheduled with `run.next` will coalesce - into the same later run loop, along with any other operations - scheduled by `run.later` that expire right around the same - time that `run.next` operations will fire. - - Note that there are often alternatives to using `run.next`. - For instance, if you'd like to schedule an operation to happen - after all DOM element operations have completed within the current - run loop, you can make use of the `afterRender` run loop queue (added - by the `ember-views` package, along with the preceding `render` queue - where all the DOM element operations happen). Example: - - ```javascript - App.MyCollectionView = Ember.CollectionView.extend({ - didInsertElement: function() { - run.scheduleOnce('afterRender', this, 'processChildElements'); - }, - processChildElements: function() { - // ... do something with collectionView's child view - // elements after they've finished rendering, which - // can't be done within the CollectionView's - // `didInsertElement` hook because that gets run - // before the child elements have been added to the DOM. - } - }); - ``` - - One benefit of the above approach compared to using `run.next` is - that you will be able to perform DOM/CSS operations before unprocessed - elements are rendered to the screen, which may prevent flickering or - other artifacts caused by delaying processing until after rendering. - - The other major benefit to the above approach is that `run.next` - introduces an element of non-determinism, which can make things much - harder to test, due to its reliance on `setTimeout`; it's much harder - to guarantee the order of scheduled operations when they are scheduled - outside of the current run loop, i.e. with `run.next`. - - @method next - @param {Object} [target] target of method to invoke - @param {Function|String} method The method to invoke. - If you pass a string it will be resolved on the - target at the time the method is invoked. - @param {Object} [args*] Optional arguments to pass to the timeout. - @return {Object} Timer information for use in cancelling, see `run.cancel`. - */ - run.next = function() { - var args = slice.call(arguments); - args.push(1); - return apply(backburner, backburner.later, args); - }; - - /** - Cancels a scheduled item. Must be a value returned by `run.later()`, - `run.once()`, `run.next()`, `run.debounce()`, or - `run.throttle()`. - - ```javascript - var runNext = run.next(myContext, function() { - // will not be executed - }); - run.cancel(runNext); - - var runLater = run.later(myContext, function() { - // will not be executed - }, 500); - run.cancel(runLater); - - var runOnce = run.once(myContext, function() { - // will not be executed - }); - run.cancel(runOnce); - - var throttle = run.throttle(myContext, function() { - // will not be executed - }, 1, false); - run.cancel(throttle); - - var debounce = run.debounce(myContext, function() { - // will not be executed - }, 1); - run.cancel(debounce); - - var debounceImmediate = run.debounce(myContext, function() { - // will be executed since we passed in true (immediate) - }, 100, true); - // the 100ms delay until this method can be called again will be cancelled - run.cancel(debounceImmediate); - ``` - - @method cancel - @param {Object} timer Timer object to cancel - @return {Boolean} true if cancelled or false/undefined if it wasn't found - */ - run.cancel = function(timer) { - return backburner.cancel(timer); - }; - - /** - Delay calling the target method until the debounce period has elapsed - with no additional debounce calls. If `debounce` is called again before - the specified time has elapsed, the timer is reset and the entire period - must pass again before the target method is called. - - This method should be used when an event may be called multiple times - but the action should only be called once when the event is done firing. - A common example is for scroll events where you only want updates to - happen once scrolling has ceased. - - ```javascript - var myFunc = function() { console.log(this.name + ' ran.'); }; - var myContext = {name: 'debounce'}; - - run.debounce(myContext, myFunc, 150); - - // less than 150ms passes - - run.debounce(myContext, myFunc, 150); - - // 150ms passes - // myFunc is invoked with context myContext - // console logs 'debounce ran.' one time. - ``` - - Immediate allows you to run the function immediately, but debounce - other calls for this function until the wait time has elapsed. If - `debounce` is called again before the specified time has elapsed, - the timer is reset and the entire period must pass again before - the method can be called again. - - ```javascript - var myFunc = function() { console.log(this.name + ' ran.'); }; - var myContext = {name: 'debounce'}; - - run.debounce(myContext, myFunc, 150, true); - - // console logs 'debounce ran.' one time immediately. - // 100ms passes - - run.debounce(myContext, myFunc, 150, true); - - // 150ms passes and nothing else is logged to the console and - // the debouncee is no longer being watched - - run.debounce(myContext, myFunc, 150, true); - - // console logs 'debounce ran.' one time immediately. - // 150ms passes and nothing else is logged to the console and - // the debouncee is no longer being watched - - ``` - - @method debounce - @param {Object} [target] target of method to invoke - @param {Function|String} method The method to invoke. - May be a function or a string. If you pass a string - then it will be looked up on the passed target. - @param {Object} [args*] Optional arguments to pass to the timeout. - @param {Number} wait Number of milliseconds to wait. - @param {Boolean} immediate Trigger the function on the leading instead - of the trailing edge of the wait interval. Defaults to false. - @return {Array} Timer information for use in cancelling, see `run.cancel`. - */ - run.debounce = function() { - return backburner.debounce.apply(backburner, arguments); - }; - - /** - Ensure that the target method is never called more frequently than - the specified spacing period. The target method is called immediately. - - ```javascript - var myFunc = function() { console.log(this.name + ' ran.'); }; - var myContext = {name: 'throttle'}; - - run.throttle(myContext, myFunc, 150); - // myFunc is invoked with context myContext - // console logs 'throttle ran.' - - // 50ms passes - run.throttle(myContext, myFunc, 150); - - // 50ms passes - run.throttle(myContext, myFunc, 150); - - // 150ms passes - run.throttle(myContext, myFunc, 150); - // myFunc is invoked with context myContext - // console logs 'throttle ran.' - ``` - - @method throttle - @param {Object} [target] target of method to invoke - @param {Function|String} method The method to invoke. - May be a function or a string. If you pass a string - then it will be looked up on the passed target. - @param {Object} [args*] Optional arguments to pass to the timeout. - @param {Number} spacing Number of milliseconds to space out requests. - @param {Boolean} immediate Trigger the function on the leading instead - of the trailing edge of the wait interval. Defaults to true. - @return {Array} Timer information for use in cancelling, see `run.cancel`. - */ - run.throttle = function() { - return backburner.throttle.apply(backburner, arguments); - }; - - // Make sure it's not an autorun during testing - function checkAutoRun() { - if (!run.currentRunLoop) { - Ember.assert("You have turned on testing mode, which disabled the run-loop's autorun." + - " You will need to wrap any code with asynchronous side-effects in a run", !Ember.testing); - } - } - - /** - Add a new named queue after the specified queue. - - The queue to add will only be added once. - - @method _addQueue - @param {String} name the name of the queue to add. - @param {String} after the name of the queue to add after. - @private - */ - run._addQueue = function(name, after) { - if (indexOf.call(run.queues, name) === -1) { - run.queues.splice(indexOf.call(run.queues, after)+1, 0, name); - } - }; - }); -enifed("ember-metal/set_properties", - ["ember-metal/property_events","ember-metal/property_set","ember-metal/keys","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var changeProperties = __dependency1__.changeProperties; - var set = __dependency2__.set; - var keys = __dependency3__["default"]; - - /** - Set a list of properties on an object. These properties are set inside - a single `beginPropertyChanges` and `endPropertyChanges` batch, so - observers will be buffered. - - ```javascript - var anObject = Ember.Object.create(); - - anObject.setProperties({ - firstName: 'Stanley', - lastName: 'Stuart', - age: 21 - }); - ``` - - @method setProperties - @param obj - @param {Object} properties - @return obj - */ - __exports__["default"] = function setProperties(obj, properties) { - if (!properties || typeof properties !== "object") { return obj; } - changeProperties(function() { - var props = keys(properties); - var propertyName; - - for (var i = 0, l = props.length; i < l; i++) { - propertyName = props[i]; - - set(obj, propertyName, properties[propertyName]); - } - }); - return obj; - } - }); -enifed("ember-metal/streams/simple", - ["ember-metal/merge","ember-metal/streams/stream","ember-metal/platform","ember-metal/streams/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var merge = __dependency1__["default"]; - var Stream = __dependency2__["default"]; - var create = __dependency3__.create; - var read = __dependency4__.read; - var isStream = __dependency4__.isStream; - - function SimpleStream(source) { - this.init(); - this.source = source; - - if (isStream(source)) { - source.subscribe(this._didChange, this); - } - } - - SimpleStream.prototype = create(Stream.prototype); - - merge(SimpleStream.prototype, { - valueFn: function() { - return read(this.source); - }, - - setValue: function(value) { - var source = this.source; - - if (isStream(source)) { - source.setValue(value); - } - }, - - setSource: function(nextSource) { - var prevSource = this.source; - if (nextSource !== prevSource) { - if (isStream(prevSource)) { - prevSource.unsubscribe(this._didChange, this); - } - - if (isStream(nextSource)) { - nextSource.subscribe(this._didChange, this); - } - - this.source = nextSource; - this.notify(); - } - }, - - _didChange: function() { - this.notify(); - }, - - _super$destroy: Stream.prototype.destroy, - - destroy: function() { - if (this._super$destroy()) { - if (isStream(this.source)) { - this.source.unsubscribe(this._didChange, this); - } - this.source = undefined; - return true; - } - } - }); - - __exports__["default"] = SimpleStream; - }); -enifed("ember-metal/streams/stream", - ["ember-metal/platform","ember-metal/path_cache","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var create = __dependency1__.create; - var getFirstKey = __dependency2__.getFirstKey; - var getTailPath = __dependency2__.getTailPath; - - function Stream(fn) { - this.init(); - this.valueFn = fn; - } - - Stream.prototype = { - isStream: true, - - init: function() { - this.state = 'dirty'; - this.cache = undefined; - this.subscribers = undefined; - this.children = undefined; - this._label = undefined; - }, - - get: function(path) { - var firstKey = getFirstKey(path); - var tailPath = getTailPath(path); - - if (this.children === undefined) { - this.children = create(null); - } - - var keyStream = this.children[firstKey]; - - if (keyStream === undefined) { - keyStream = this._makeChildStream(firstKey, path); - this.children[firstKey] = keyStream; - } - - if (tailPath === undefined) { - return keyStream; - } else { - return keyStream.get(tailPath); - } - }, - - value: function() { - if (this.state === 'clean') { - return this.cache; - } else if (this.state === 'dirty') { - this.state = 'clean'; - return this.cache = this.valueFn(); - } - // TODO: Ensure value is never called on a destroyed stream - // so that we can uncomment this assertion. - // - // Ember.assert("Stream error: value was called in an invalid state: " + this.state); - }, - - valueFn: function() { - throw new Error("Stream error: valueFn not implemented"); - }, - - setValue: function() { - throw new Error("Stream error: setValue not implemented"); - }, - - notify: function() { - this.notifyExcept(); - }, - - notifyExcept: function(callbackToSkip, contextToSkip) { - if (this.state === 'clean') { - this.state = 'dirty'; - this._notifySubscribers(callbackToSkip, contextToSkip); - } - }, - - subscribe: function(callback, context) { - if (this.subscribers === undefined) { - this.subscribers = [callback, context]; - } else { - this.subscribers.push(callback, context); - } - }, - - unsubscribe: function(callback, context) { - var subscribers = this.subscribers; - - if (subscribers !== undefined) { - for (var i = 0, l = subscribers.length; i < l; i += 2) { - if (subscribers[i] === callback && subscribers[i+1] === context) { - subscribers.splice(i, 2); - return; - } - } - } - }, - - _notifySubscribers: function(callbackToSkip, contextToSkip) { - var subscribers = this.subscribers; - - if (subscribers !== undefined) { - for (var i = 0, l = subscribers.length; i < l; i += 2) { - var callback = subscribers[i]; - var context = subscribers[i+1]; - - if (callback === callbackToSkip && context === contextToSkip) { - continue; - } - - if (context === undefined) { - callback(this); - } else { - callback.call(context, this); - } - } - } - }, - - destroy: function() { - if (this.state !== 'destroyed') { - this.state = 'destroyed'; - - var children = this.children; - for (var key in children) { - children[key].destroy(); - } - - return true; - } - }, - - isGlobal: function() { - var stream = this; - while (stream !== undefined) { - if (stream._isRoot) { - return stream._isGlobal; - } - stream = stream.source; - } - } - }; - - __exports__["default"] = Stream; - }); -enifed("ember-metal/streams/stream_binding", - ["ember-metal/platform","ember-metal/merge","ember-metal/run_loop","ember-metal/streams/stream","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var create = __dependency1__.create; - var merge = __dependency2__["default"]; - var run = __dependency3__["default"]; - var Stream = __dependency4__["default"]; - - function StreamBinding(stream) { - Ember.assert("StreamBinding error: tried to bind to object that is not a stream", stream && stream.isStream); - - this.init(); - this.stream = stream; - this.senderCallback = undefined; - this.senderContext = undefined; - this.senderValue = undefined; - - stream.subscribe(this._onNotify, this); - } - - StreamBinding.prototype = create(Stream.prototype); - - merge(StreamBinding.prototype, { - valueFn: function() { - return this.stream.value(); - }, - - _onNotify: function() { - this._scheduleSync(undefined, undefined, this); - }, - - setValue: function(value, callback, context) { - this._scheduleSync(value, callback, context); - }, - - _scheduleSync: function(value, callback, context) { - if (this.senderCallback === undefined && this.senderContext === undefined) { - this.senderCallback = callback; - this.senderContext = context; - this.senderValue = value; - run.schedule('sync', this, this._sync); - } else if (this.senderContext !== this) { - this.senderCallback = callback; - this.senderContext = context; - this.senderValue = value; - } - }, - - _sync: function() { - if (this.state === 'destroyed') { - return; - } - - if (this.senderContext !== this) { - this.stream.setValue(this.senderValue); - } - - var senderCallback = this.senderCallback; - var senderContext = this.senderContext; - this.senderCallback = undefined; - this.senderContext = undefined; - this.senderValue = undefined; - - // Force StreamBindings to always notify - this.state = 'clean'; - - this.notifyExcept(senderCallback, senderContext); - }, - - _super$destroy: Stream.prototype.destroy, - - destroy: function() { - if (this._super$destroy()) { - this.stream.unsubscribe(this._onNotify, this); - return true; - } - } - }); - - __exports__["default"] = StreamBinding; - }); -enifed("ember-metal/streams/utils", - ["./stream","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Stream = __dependency1__["default"]; - - /** - Check whether an object is a stream or not - - @private - @function isStream - @param {Object|Stream} object object to check whether it is a stream - @return {Boolean} `true` if the object is a stream, `false` otherwise - */ - function isStream(object) { - return object && object.isStream; - } - - __exports__.isStream = isStream;/** - A method of subscribing to a stream which is safe for use with a non-stream - object. If a non-stream object is passed, the function does nothing. - - @private - @function subscribe - @param {Object|Stream} object object or stream to potentially subscribe to - @param {Function} callback function to run when stream value changes - @param {Object} [context] the callback will be executed with this context if it - is provided - */ - function subscribe(object, callback, context) { - if (object && object.isStream) { - object.subscribe(callback, context); - } - } - - __exports__.subscribe = subscribe;/** - A method of unsubscribing from a stream which is safe for use with a non-stream - object. If a non-stream object is passed, the function does nothing. - - @private - @function unsubscribe - @param {Object|Stream} object object or stream to potentially unsubscribe from - @param {Function} callback function originally passed to `subscribe()` - @param {Object} [context] object originally passed to `subscribe()` - */ - function unsubscribe(object, callback, context) { - if (object && object.isStream) { - object.unsubscribe(callback, context); - } - } - - __exports__.unsubscribe = unsubscribe;/** - Retrieve the value of a stream, or in the case a non-stream object is passed, - return the object itself. - - @private - @function read - @param {Object|Stream} object object to return the value of - @return the stream's current value, or the non-stream object itself - */ - function read(object) { - if (object && object.isStream) { - return object.value(); - } else { - return object; - } - } - - __exports__.read = read;/** - Map an array, replacing any streams with their values. - - @private - @function readArray - @param {Array} array The array to read values from - @return {Array} a new array of the same length with the values of non-stream - objects mapped from their original positions untouched, and - the values of stream objects retaining their original position - and replaced with the stream's current value. - */ - function readArray(array) { - var length = array.length; - var ret = new Array(length); - for (var i = 0; i < length; i++) { - ret[i] = read(array[i]); - } - return ret; - } - - __exports__.readArray = readArray;/** - Map a hash, replacing any stream property values with the current value of that - stream. - - @private - @function readHash - @param {Object} object The hash to read keys and values from - @return {Object} a new object with the same keys as the passed object. The - property values in the new object are the original values in - the case of non-stream objects, and the streams' current - values in the case of stream objects. - */ - function readHash(object) { - var ret = {}; - for (var key in object) { - ret[key] = read(object[key]); - } - return ret; - } - - __exports__.readHash = readHash;/** - Check whether an array contains any stream values - - @private - @function scanArray - @param {Array} array array given to a handlebars helper - @return {Boolean} `true` if the array contains a stream/bound value, `false` - otherwise - */ - function scanArray(array) { - var length = array.length; - var containsStream = false; - - for (var i = 0; i < length; i++){ - if (isStream(array[i])) { - containsStream = true; - break; - } - } - - return containsStream; - } - - __exports__.scanArray = scanArray;/** - Check whether a hash has any stream property values - - @private - @function scanHash - @param {Object} hash "hash" argument given to a handlebars helper - @return {Boolean} `true` if the object contains a stream/bound value, `false` - otherwise - */ - function scanHash(hash) { - var containsStream = false; - - for (var prop in hash) { - if (isStream(hash[prop])) { - containsStream = true; - break; - } - } - - return containsStream; - } - - __exports__.scanHash = scanHash;/** - Join an array, with any streams replaced by their current values - - @private - @function concat - @param {Array} array An array containing zero or more stream objects and - zero or more non-stream objects - @param {String} separator string to be used to join array elements - @return {String} String with array elements concatenated and joined by the - provided separator, and any stream array members having been - replaced by the current value of the stream - */ - function concat(array, separator) { - // TODO: Create subclass ConcatStream < Stream. Defer - // subscribing to streams until the value() is called. - var hasStream = scanArray(array); - if (hasStream) { - var i, l; - var stream = new Stream(function() { - return readArray(array).join(separator); - }); - - for (i = 0, l=array.length; i < l; i++) { - subscribe(array[i], stream.notify, stream); - } - - return stream; - } else { - return array.join(separator); - } - } - - __exports__.concat = concat;/** - Generate a new stream by providing a source stream and a function that can - be used to transform the stream's value. In the case of a non-stream object, - returns the result of the function. - - The value to transform would typically be available to the function you pass - to `chain()` via scope. For example: - - ```javascript - var source = ...; // stream returning a number - // or a numeric (non-stream) object - var result = chain(source, function(){ - var currentValue = read(source); - return currentValue + 1; - }); - ``` - - In the example, result is a stream if source is a stream, or a number of - source was numeric. - - @private - @function chain - @param {Object|Stream} value A stream or non-stream object - @param {Function} fn function to be run when the stream value changes, or to - be run once in the case of a non-stream object - @return {Object|Stream} In the case of a stream `value` parameter, a new - stream that will be updated with the return value of - the provided function `fn`. In the case of a - non-stream object, the return value of the provided - function `fn`. - */ - function chain(value, fn) { - if (isStream(value)) { - var stream = new Stream(fn); - subscribe(value, stream.notify, stream); - return stream; - } else { - return fn(); - } - } - - __exports__.chain = chain; - }); -enifed("ember-metal/utils", - ["ember-metal/core","ember-metal/platform","ember-metal/array","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - // Remove "use strict"; from transpiled module until - // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed - // - // REMOVE_USE_STRICT: true - - var Ember = __dependency1__["default"]; - var o_defineProperty = __dependency2__.defineProperty; - var canDefineNonEnumerableProperties = __dependency2__.canDefineNonEnumerableProperties; - var hasPropertyAccessors = __dependency2__.hasPropertyAccessors; - var o_create = __dependency2__.create; - - var forEach = __dependency3__.forEach; - - /** - @module ember-metal - */ - - /** - Previously we used `Ember.$.uuid`, however `$.uuid` has been removed from - jQuery master. We'll just bootstrap our own uuid now. - - @private - @return {Number} the uuid - */ - var _uuid = 0; - - /** - Generates a universally unique identifier. This method - is used internally by Ember for assisting with - the generation of GUID's and other unique identifiers - such as `bind-attr` data attributes. - - @public - @return {Number} [description] - */ - function uuid() { - return ++_uuid; - } - - __exports__.uuid = uuid;/** - Prefix used for guids through out Ember. - @private - @property GUID_PREFIX - @for Ember - @type String - @final - */ - var GUID_PREFIX = 'ember'; - - // Used for guid generation... - var numberCache = []; - var stringCache = {}; - - /** - Strongly hint runtimes to intern the provided string. - - When do I need to use this function? - - For the most part, never. Pre-mature optimization is bad, and often the - runtime does exactly what you need it to, and more often the trade-off isn't - worth it. - - Why? - - Runtimes store strings in at least 2 different representations: - Ropes and Symbols (interned strings). The Rope provides a memory efficient - data-structure for strings created from concatenation or some other string - manipulation like splitting. - - Unfortunately checking equality of different ropes can be quite costly as - runtimes must resort to clever string comparison algorithims. These - algorithims typically cost in proportion to the length of the string. - Luckily, this is where the Symbols (interned strings) shine. As Symbols are - unique by their string content, equality checks can be done by pointer - comparison. - - How do I know if my string is a rope or symbol? - - Typically (warning general sweeping statement, but truthy in runtimes at - present) static strings created as part of the JS source are interned. - Strings often used for comparisons can be interned at runtime if some - criteria are met. One of these criteria can be the size of the entire rope. - For example, in chrome 38 a rope longer then 12 characters will not - intern, nor will segments of that rope. - - Some numbers: http://jsperf.com/eval-vs-keys/8 - - Known Trick™ - - @private - @return {String} interned version of the provided string - */ - function intern(str) { - var obj = {}; - obj[str] = 1; - for (var key in obj) { - if (key === str) return key; - } - return str; - } - - /** - A unique key used to assign guids and other private metadata to objects. - If you inspect an object in your browser debugger you will often see these. - They can be safely ignored. - - On browsers that support it, these properties are added with enumeration - disabled so they won't show up when you iterate over your properties. - - @private - @property GUID_KEY - @for Ember - @type String - @final - */ - var GUID_KEY = intern('__ember' + (+ new Date())); - - var GUID_DESC = { - writable: false, - configurable: false, - enumerable: false, - value: null - }; - - /** - Generates a new guid, optionally saving the guid to the object that you - pass in. You will rarely need to use this method. Instead you should - call `Ember.guidFor(obj)`, which return an existing guid if available. - - @private - @method generateGuid - @for Ember - @param {Object} [obj] Object the guid will be used for. If passed in, the guid will - be saved on the object and reused whenever you pass the same object - again. - - If no object is passed, just generate a new guid. - @param {String} [prefix] Prefix to place in front of the guid. Useful when you want to - separate the guid into separate namespaces. - @return {String} the guid - */ - function generateGuid(obj, prefix) { - if (!prefix) prefix = GUID_PREFIX; - var ret = (prefix + uuid()); - if (obj) { - if (obj[GUID_KEY] === null) { - obj[GUID_KEY] = ret; - } else { - GUID_DESC.value = ret; - o_defineProperty(obj, GUID_KEY, GUID_DESC); - } - } - return ret; - } - - __exports__.generateGuid = generateGuid;/** - Returns a unique id for the object. If the object does not yet have a guid, - one will be assigned to it. You can call this on any object, - `Ember.Object`-based or not, but be aware that it will add a `_guid` - property. - - You can also use this method on DOM Element objects. - - @private - @method guidFor - @for Ember - @param {Object} obj any object, string, number, Element, or primitive - @return {String} the unique guid for this instance. - */ - function guidFor(obj) { - - // special cases where we don't want to add a key to object - if (obj === undefined) return "(undefined)"; - if (obj === null) return "(null)"; - - var ret; - var type = typeof obj; - - // Don't allow prototype changes to String etc. to change the guidFor - switch(type) { - case 'number': - ret = numberCache[obj]; - if (!ret) ret = numberCache[obj] = 'nu'+obj; - return ret; - - case 'string': - ret = stringCache[obj]; - if (!ret) ret = stringCache[obj] = 'st' + uuid(); - return ret; - - case 'boolean': - return obj ? '(true)' : '(false)'; - - default: - if (obj[GUID_KEY]) return obj[GUID_KEY]; - if (obj === Object) return '(Object)'; - if (obj === Array) return '(Array)'; - ret = GUID_PREFIX + uuid(); - - if (obj[GUID_KEY] === null) { - obj[GUID_KEY] = ret; - } else { - GUID_DESC.value = ret; - o_defineProperty(obj, GUID_KEY, GUID_DESC); - } - return ret; - } - } - - __exports__.guidFor = guidFor;// .......................................................... - // META - // - - var META_DESC = { - writable: true, - configurable: false, - enumerable: false, - value: null - }; - - function Meta(obj) { - this.descs = {}; - this.watching = {}; - this.cache = {}; - this.cacheMeta = {}; - this.source = obj; - this.deps = undefined; - this.listeners = undefined; - this.mixins = undefined; - this.bindings = undefined; - this.chains = undefined; - this.values = undefined; - this.proto = undefined; - } - - Meta.prototype = { - chainWatchers: null - }; - - if (!canDefineNonEnumerableProperties) { - // on platforms that don't support enumerable false - // make meta fail jQuery.isPlainObject() to hide from - // jQuery.extend() by having a property that fails - // hasOwnProperty check. - Meta.prototype.__preventPlainObject__ = true; - - // Without non-enumerable properties, meta objects will be output in JSON - // unless explicitly suppressed - Meta.prototype.toJSON = function () { }; - } - - // Placeholder for non-writable metas. - var EMPTY_META = new Meta(null); - - - if (hasPropertyAccessors) { - EMPTY_META.values = {}; - } - - - /** - Retrieves the meta hash for an object. If `writable` is true ensures the - hash is writable for this object as well. - - The meta object contains information about computed property descriptors as - well as any watched properties and other information. You generally will - not access this information directly but instead work with higher level - methods that manipulate this hash indirectly. - - @method meta - @for Ember - @private - - @param {Object} obj The object to retrieve meta for - @param {Boolean} [writable=true] Pass `false` if you do not intend to modify - the meta hash, allowing the method to avoid making an unnecessary copy. - @return {Object} the meta hash for an object - */ - function meta(obj, writable) { - var ret = obj['__ember_meta__']; - if (writable===false) return ret || EMPTY_META; - - if (!ret) { - if (canDefineNonEnumerableProperties) o_defineProperty(obj, '__ember_meta__', META_DESC); - - ret = new Meta(obj); - - - if (hasPropertyAccessors) { - ret.values = {}; - } - - - obj['__ember_meta__'] = ret; - - // make sure we don't accidentally try to create constructor like desc - ret.descs.constructor = null; - - } else if (ret.source !== obj) { - if (canDefineNonEnumerableProperties) o_defineProperty(obj, '__ember_meta__', META_DESC); - - ret = o_create(ret); - ret.descs = o_create(ret.descs); - ret.watching = o_create(ret.watching); - ret.cache = {}; - ret.cacheMeta = {}; - ret.source = obj; - - - if (hasPropertyAccessors) { - ret.values = o_create(ret.values); - } - - - obj['__ember_meta__'] = ret; - } - return ret; - } - - function getMeta(obj, property) { - var _meta = meta(obj, false); - return _meta[property]; - } - - __exports__.getMeta = getMeta;function setMeta(obj, property, value) { - var _meta = meta(obj, true); - _meta[property] = value; - return value; - } - - __exports__.setMeta = setMeta;/** - @deprecated - @private - - In order to store defaults for a class, a prototype may need to create - a default meta object, which will be inherited by any objects instantiated - from the class's constructor. - - However, the properties of that meta object are only shallow-cloned, - so if a property is a hash (like the event system's `listeners` hash), - it will by default be shared across all instances of that class. - - This method allows extensions to deeply clone a series of nested hashes or - other complex objects. For instance, the event system might pass - `['listeners', 'foo:change', 'ember157']` to `prepareMetaPath`, which will - walk down the keys provided. - - For each key, if the key does not exist, it is created. If it already - exists and it was inherited from its constructor, the constructor's - key is cloned. - - You can also pass false for `writable`, which will simply return - undefined if `prepareMetaPath` discovers any part of the path that - shared or undefined. - - @method metaPath - @for Ember - @param {Object} obj The object whose meta we are examining - @param {Array} path An array of keys to walk down - @param {Boolean} writable whether or not to create a new meta - (or meta property) if one does not already exist or if it's - shared with its constructor - */ - function metaPath(obj, path, writable) { - Ember.deprecate("Ember.metaPath is deprecated and will be removed from future releases."); - var _meta = meta(obj, writable); - var keyName, value; - - for (var i=0, l=path.length; i 1) { - watching[keyName]--; - } - } - - __exports__.unwatchKey = unwatchKey; - }); -enifed("ember-metal/watch_path", - ["ember-metal/utils","ember-metal/chains","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var metaFor = __dependency1__.meta; - var typeOf = __dependency1__.typeOf; - var ChainNode = __dependency2__.ChainNode; - - // get the chains for the current object. If the current object has - // chains inherited from the proto they will be cloned and reconfigured for - // the current object. - function chainsFor(obj, meta) { - var m = meta || metaFor(obj); - var ret = m.chains; - if (!ret) { - ret = m.chains = new ChainNode(null, null, obj); - } else if (ret.value() !== obj) { - ret = m.chains = ret.copy(obj); - } - return ret; - } - - function watchPath(obj, keyPath, meta) { - // can't watch length on Array - it is special... - if (keyPath === 'length' && typeOf(obj) === 'array') { return; } - - var m = meta || metaFor(obj); - var watching = m.watching; - - if (!watching[keyPath]) { // activate watching first time - watching[keyPath] = 1; - chainsFor(obj, m).add(keyPath); - } else { - watching[keyPath] = (watching[keyPath] || 0) + 1; - } - } - - __exports__.watchPath = watchPath;function unwatchPath(obj, keyPath, meta) { - var m = meta || metaFor(obj); - var watching = m.watching; - - if (watching[keyPath] === 1) { - watching[keyPath] = 0; - chainsFor(obj, m).remove(keyPath); - } else if (watching[keyPath] > 1) { - watching[keyPath]--; - } - } - - __exports__.unwatchPath = unwatchPath; - }); -enifed("ember-metal/watching", - ["ember-metal/utils","ember-metal/chains","ember-metal/watch_key","ember-metal/watch_path","ember-metal/path_cache","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - /** - @module ember-metal - */ - - var typeOf = __dependency1__.typeOf; - var removeChainWatcher = __dependency2__.removeChainWatcher; - var flushPendingChains = __dependency2__.flushPendingChains; - var watchKey = __dependency3__.watchKey; - var unwatchKey = __dependency3__.unwatchKey; - var watchPath = __dependency4__.watchPath; - var unwatchPath = __dependency4__.unwatchPath; - - var isPath = __dependency5__.isPath; - - /** - Starts watching a property on an object. Whenever the property changes, - invokes `Ember.propertyWillChange` and `Ember.propertyDidChange`. This is the - primitive used by observers and dependent keys; usually you will never call - this method directly but instead use higher level methods like - `Ember.addObserver()` - - @private - @method watch - @for Ember - @param obj - @param {String} keyName - */ - function watch(obj, _keyPath, m) { - // can't watch length on Array - it is special... - if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } - - if (!isPath(_keyPath)) { - watchKey(obj, _keyPath, m); - } else { - watchPath(obj, _keyPath, m); - } - } - - __exports__.watch = watch; - - function isWatching(obj, key) { - var meta = obj['__ember_meta__']; - return (meta && meta.watching[key]) > 0; - } - - __exports__.isWatching = isWatching;watch.flushPending = flushPendingChains; - - function unwatch(obj, _keyPath, m) { - // can't watch length on Array - it is special... - if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } - - if (!isPath(_keyPath)) { - unwatchKey(obj, _keyPath, m); - } else { - unwatchPath(obj, _keyPath, m); - } - } - - __exports__.unwatch = unwatch;var NODE_STACK = []; - - /** - Tears down the meta on an object so that it can be garbage collected. - Multiple calls will have no effect. - - @method destroy - @for Ember - @param {Object} obj the object to destroy - @return {void} - */ - function destroy(obj) { - var meta = obj['__ember_meta__'], node, nodes, key, nodeObject; - if (meta) { - obj['__ember_meta__'] = null; - // remove chainWatchers to remove circular references that would prevent GC - node = meta.chains; - if (node) { - NODE_STACK.push(node); - // process tree - while (NODE_STACK.length > 0) { - node = NODE_STACK.pop(); - // push children - nodes = node._chains; - if (nodes) { - for (key in nodes) { - if (nodes.hasOwnProperty(key)) { - NODE_STACK.push(nodes[key]); - } - } - } - // remove chainWatcher in node object - if (node._watching) { - nodeObject = node._object; - if (nodeObject) { - removeChainWatcher(nodeObject, node._key, node); - } - } - } - } - } - } - - __exports__.destroy = destroy; - }); -enifed("ember-routing-htmlbars", - ["ember-metal/core","ember-htmlbars/helpers","ember-routing-htmlbars/helpers/outlet","ember-routing-htmlbars/helpers/render","ember-routing-htmlbars/helpers/link-to","ember-routing-htmlbars/helpers/action","ember-routing-htmlbars/helpers/query-params","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - /** - Ember Routing HTMLBars Helpers - - @module ember - @submodule ember-routing-htmlbars - @requires ember-routing - */ - - var Ember = __dependency1__["default"]; - - var registerHelper = __dependency2__.registerHelper; - - var outletHelper = __dependency3__.outletHelper; - var renderHelper = __dependency4__.renderHelper; - var linkToHelper = __dependency5__.linkToHelper; - var deprecatedLinkToHelper = __dependency5__.deprecatedLinkToHelper; - var actionHelper = __dependency6__.actionHelper; - var queryParamsHelper = __dependency7__.queryParamsHelper; - - registerHelper('outlet', outletHelper); - registerHelper('render', renderHelper); - registerHelper('link-to', linkToHelper); - registerHelper('linkTo', deprecatedLinkToHelper); - registerHelper('action', actionHelper); - registerHelper('query-params', queryParamsHelper); - - __exports__["default"] = Ember; - }); -enifed("ember-routing-htmlbars/helpers/action", - ["ember-metal/core","ember-metal/utils","ember-metal/run_loop","ember-views/streams/utils","ember-views/system/utils","ember-views/system/action_manager","ember-metal/array","ember-metal/streams/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-routing-htmlbars - */ - - var Ember = __dependency1__["default"]; - // Handlebars, uuid, FEATURES, assert, deprecate - var uuid = __dependency2__.uuid; - var run = __dependency3__["default"]; - var readUnwrappedModel = __dependency4__.readUnwrappedModel; - var isSimpleClick = __dependency5__.isSimpleClick; - var ActionManager = __dependency6__["default"]; - var indexOf = __dependency7__.indexOf; - var isStream = __dependency8__.isStream; - - function actionArgs(parameters, actionName) { - var ret, i, l; - - if (actionName === undefined) { - ret = new Array(parameters.length); - for (i=0, l=parameters.length;i= 0) { - return true; - } - - for (var i=0, l=keys.length;i - click me - - ``` - - And application code - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - actions: { - anActionName: function() { - } - } - }); - ``` - - Will result in the following rendered HTML - - ```html -
    -
    - click me -
    -
    - ``` - - Clicking "click me" will trigger the `anActionName` action of the - `App.ApplicationController`. In this case, no additional parameters will be passed. - - If you provide additional parameters to the helper: - - ```handlebars - - ``` - - Those parameters will be passed along as arguments to the JavaScript - function implementing the action. - - ### Event Propagation - - Events triggered through the action helper will automatically have - `.preventDefault()` called on them. You do not need to do so in your event - handlers. If you need to allow event propagation (to handle file inputs for - example) you can supply the `preventDefault=false` option to the `{{action}}` helper: - - ```handlebars -
    - - -
    - ``` - - To disable bubbling, pass `bubbles=false` to the helper: - - ```handlebars - - ``` - - If you need the default handler to trigger you should either register your - own event handler, or use event methods on your view class. See [Ember.View](/api/classes/Ember.View.html) - 'Responding to Browser Events' for more information. - - ### Specifying DOM event type - - By default the `{{action}}` helper registers for DOM `click` events. You can - supply an `on` option to the helper to specify a different DOM event name: - - ```handlebars -
    - click me -
    - ``` - - See `Ember.View` 'Responding to Browser Events' for a list of - acceptable DOM event names. - - ### Specifying whitelisted modifier keys - - By default the `{{action}}` helper will ignore click event with pressed modifier - keys. You can supply an `allowedKeys` option to specify which keys should not be ignored. - - ```handlebars -
    - click me -
    - ``` - - This way the `{{action}}` will fire when clicking with the alt key pressed down. - - Alternatively, supply "any" to the `allowedKeys` option to accept any combination of modifier keys. - - ```handlebars -
    - click me with any key pressed -
    - ``` - - ### Specifying a Target - - There are several possible target objects for `{{action}}` helpers: - - In a typical Ember application, where templates are managed through use of the - `{{outlet}}` helper, actions will bubble to the current controller, then - to the current route, and then up the route hierarchy. - - Alternatively, a `target` option can be provided to the helper to change - which object will receive the method call. This option must be a path - to an object, accessible in the current context: - - ```handlebars - {{! the application template }} -
    - click me -
    - ``` - - ```javascript - App.ApplicationView = Ember.View.extend({ - actions: { - anActionName: function(){} - } - }); - - ``` - - ### Additional Parameters - - You may specify additional parameters to the `{{action}}` helper. These - parameters are passed along as the arguments to the JavaScript function - implementing the action. - - ```handlebars - {{#each person in people}} -
    - click me -
    - {{/each}} - ``` - - Clicking "click me" will trigger the `edit` method on the current controller - with the value of `person` as a parameter. - - @method action - @for Ember.Handlebars.helpers - @param {String} actionName - @param {Object} [context]* - @param {Hash} options - */ - function actionHelper(params, hash, options, env) { - - var target; - if (!hash.target) { - target = this.getStream('controller'); - } else if (isStream(hash.target)) { - target = hash.target; - } else { - target = this.getStream(hash.target); - } - - // Ember.assert("You specified a quoteless path to the {{action}} helper which did not resolve to an action name (a string). Perhaps you meant to use a quoted actionName? (e.g. {{action 'save'}}).", !params[0].isStream); - // Ember.deprecate("You specified a quoteless path to the {{action}} helper which did not resolve to an action name (a string). Perhaps you meant to use a quoted actionName? (e.g. {{action 'save'}}).", params[0].isStream); - - var actionOptions = { - eventName: hash.on || "click", - parameters: params.slice(1), - view: this, - bubbles: hash.bubbles, - preventDefault: hash.preventDefault, - target: target, - withKeyCode: hash.withKeyCode - }; - - var actionId = ActionHelper.registerAction(params[0], actionOptions, hash.allowedKeys); - env.dom.setAttribute(options.element, 'data-ember-action', actionId); - } - - __exports__.actionHelper = actionHelper; - }); -enifed("ember-routing-htmlbars/helpers/link-to", - ["ember-metal/core","ember-routing-views/views/link","ember-metal/streams/utils","ember-runtime/mixins/controller","ember-htmlbars/utils/string","ember-htmlbars","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-routing-handlebars - */ - - var Ember = __dependency1__["default"]; - // assert - var LinkView = __dependency2__.LinkView; - var read = __dependency3__.read; - var isStream = __dependency3__.isStream; - var ControllerMixin = __dependency4__["default"]; - var escapeExpression = __dependency5__.escapeExpression; - - // We need the HTMLBars view helper from ensure ember-htmlbars. - // This ensures it is loaded first: - - /** - The `{{link-to}}` helper renders a link to the supplied - `routeName` passing an optionally supplied model to the - route as its `model` context of the route. The block - for `{{link-to}}` becomes the innerHTML of the rendered - element: - - ```handlebars - {{#link-to 'photoGallery'}} - Great Hamster Photos - {{/link-to}} - ``` - - You can also use an inline form of `{{link-to}}` helper by - passing the link text as the first argument - to the helper: - - ```handlebars - {{link-to 'Great Hamster Photos' 'photoGallery'}} - ``` - - Both will result in: - - ```html - - Great Hamster Photos - - ``` - - ### Supplying a tagName - By default `{{link-to}}` renders an `` element. This can - be overridden for a single use of `{{link-to}}` by supplying - a `tagName` option: - - ```handlebars - {{#link-to 'photoGallery' tagName="li"}} - Great Hamster Photos - {{/link-to}} - ``` - - ```html -
  • - Great Hamster Photos -
  • - ``` - - To override this option for your entire application, see - "Overriding Application-wide Defaults". - - ### Disabling the `link-to` helper - By default `{{link-to}}` is enabled. - any passed value to `disabled` helper property will disable the `link-to` helper. - - static use: the `disabled` option: - - ```handlebars - {{#link-to 'photoGallery' disabled=true}} - Great Hamster Photos - {{/link-to}} - ``` - - dynamic use: the `disabledWhen` option: - - ```handlebars - {{#link-to 'photoGallery' disabledWhen=controller.someProperty}} - Great Hamster Photos - {{/link-to}} - ``` - - any passed value to `disabled` will disable it except `undefined`. - to ensure that only `true` disable the `link-to` helper you can - override the global behaviour of `Ember.LinkView`. - - ```javascript - Ember.LinkView.reopen({ - disabled: Ember.computed(function(key, value) { - if (value !== undefined) { - this.set('_isDisabled', value === true); - } - return value === true ? get(this, 'disabledClass') : false; - }) - }); - ``` - - see "Overriding Application-wide Defaults" for more. - - ### Handling `href` - `{{link-to}}` will use your application's Router to - fill the element's `href` property with a url that - matches the path to the supplied `routeName` for your - routers's configured `Location` scheme, which defaults - to Ember.HashLocation. - - ### Handling current route - `{{link-to}}` will apply a CSS class name of 'active' - when the application's current route matches - the supplied routeName. For example, if the application's - current route is 'photoGallery.recent' the following - use of `{{link-to}}`: - - ```handlebars - {{#link-to 'photoGallery.recent'}} - Great Hamster Photos from the last week - {{/link-to}} - ``` - - will result in - - ```html -
    - Great Hamster Photos - - ``` - - The CSS class name used for active classes can be customized - for a single use of `{{link-to}}` by passing an `activeClass` - option: - - ```handlebars - {{#link-to 'photoGallery.recent' activeClass="current-url"}} - Great Hamster Photos from the last week - {{/link-to}} - ``` - - ```html - - Great Hamster Photos - - ``` - - To override this option for your entire application, see - "Overriding Application-wide Defaults". - - ### Supplying a model - An optional model argument can be used for routes whose - paths contain dynamic segments. This argument will become - the model context of the linked route: - - ```javascript - App.Router.map(function() { - this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); - }); - ``` - - ```handlebars - {{#link-to 'photoGallery' aPhoto}} - {{aPhoto.title}} - {{/link-to}} - ``` - - ```html - - Tomster - - ``` - - ### Supplying multiple models - For deep-linking to route paths that contain multiple - dynamic segments, multiple model arguments can be used. - As the router transitions through the route path, each - supplied model argument will become the context for the - route with the dynamic segments: - - ```javascript - App.Router.map(function() { - this.resource("photoGallery", {path: "hamster-photos/:photo_id"}, function() { - this.route("comment", {path: "comments/:comment_id"}); - }); - }); - ``` - This argument will become the model context of the linked route: - - ```handlebars - {{#link-to 'photoGallery.comment' aPhoto comment}} - {{comment.body}} - {{/link-to}} - ``` - - ```html - - A+++ would snuggle again. - - ``` - - ### Supplying an explicit dynamic segment value - If you don't have a model object available to pass to `{{link-to}}`, - an optional string or integer argument can be passed for routes whose - paths contain dynamic segments. This argument will become the value - of the dynamic segment: - - ```javascript - App.Router.map(function() { - this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); - }); - ``` - - ```handlebars - {{#link-to 'photoGallery' aPhotoId}} - {{aPhoto.title}} - {{/link-to}} - ``` - - ```html - - Tomster - - ``` - - When transitioning into the linked route, the `model` hook will - be triggered with parameters including this passed identifier. - - ### Allowing Default Action - - By default the `{{link-to}}` helper prevents the default browser action - by calling `preventDefault()` as this sort of action bubbling is normally - handled internally and we do not want to take the browser to a new URL (for - example). - - If you need to override this behavior specify `preventDefault=false` in - your template: - - ```handlebars - {{#link-to 'photoGallery' aPhotoId preventDefault=false}} - {{aPhotoId.title}} - {{/link-to}} - ``` - - ### Overriding attributes - You can override any given property of the Ember.LinkView - that is generated by the `{{link-to}}` helper by passing - key/value pairs, like so: - - ```handlebars - {{#link-to aPhoto tagName='li' title='Following this link will change your life' classNames='pic sweet'}} - Uh-mazing! - {{/link-to}} - ``` - - See [Ember.LinkView](/api/classes/Ember.LinkView.html) for a - complete list of overrideable properties. Be sure to also - check out inherited properties of `LinkView`. - - ### Overriding Application-wide Defaults - ``{{link-to}}`` creates an instance of Ember.LinkView - for rendering. To override options for your entire - application, reopen Ember.LinkView and supply the - desired values: - - ``` javascript - Ember.LinkView.reopen({ - activeClass: "is-active", - tagName: 'li' - }) - ``` - - It is also possible to override the default event in - this manner: - - ``` javascript - Ember.LinkView.reopen({ - eventName: 'customEventName' - }); - ``` - - @method link-to - @for Ember.Handlebars.helpers - @param {String} routeName - @param {Object} [context]* - @param [options] {Object} Handlebars key/value pairs of options, you can override any property of Ember.LinkView - @return {String} HTML string - @see {Ember.LinkView} - */ - function linkToHelper(params, hash, options, env) { - var shouldEscape = !hash.unescaped; - var queryParamsObject; - - Ember.assert("You must provide one or more parameters to the link-to helper.", params.length); - - var lastParam = params[params.length - 1]; - - if (lastParam && lastParam.isQueryParams) { - hash.queryParamsObject = queryParamsObject = params.pop(); - } - - if (hash.disabledWhen) { - hash.disabled = hash.disabledWhen; - delete hash.disabledWhen; - } - - if (!options.template) { - var linkTitle = params.shift(); - - if (isStream(linkTitle)) { - hash.linkTitle = { stream: linkTitle }; - } - - options.template = { - isHTMLBars: true, - render: function() { - var value = read(linkTitle); - if (value) { - return shouldEscape ? escapeExpression(value) : value; - } else { - return ""; - } - } - }; - } - - for (var i = 0; i < params.length; i++) { - if (isStream(params[i])) { - var lazyValue = params[i]; - - if (!lazyValue._isController) { - while (ControllerMixin.detect(lazyValue.value())) { - lazyValue = lazyValue.get('model'); - } - } - - params[i] = lazyValue; - } - } - - hash.params = params; - - options.helperName = options.helperName || 'link-to'; - - return env.helpers.view.helperFunction.call(this, [LinkView], hash, options, env); - } - - /** - See [link-to](/api/classes/Ember.Handlebars.helpers.html#method_link-to) - - @method linkTo - @for Ember.Handlebars.helpers - @deprecated - @param {String} routeName - @param {Object} [context]* - @return {String} HTML string - */ - function deprecatedLinkToHelper(params, hash, options, env) { - Ember.deprecate("The 'linkTo' view helper is deprecated in favor of 'link-to'"); - - return env.helpers['link-to'].helperFunction.call(this, params, hash, options, env); - } - - __exports__.deprecatedLinkToHelper = deprecatedLinkToHelper; - __exports__.linkToHelper = linkToHelper; - }); -enifed("ember-routing-htmlbars/helpers/outlet", - ["ember-metal/core","ember-metal/property_set","ember-routing-views/views/outlet","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-routing-htmlbars - */ - - var Ember = __dependency1__["default"]; - // assert - var set = __dependency2__.set; - var OutletView = __dependency3__.OutletView; - - /** - The `outlet` helper is a placeholder that the router will fill in with - the appropriate template based on the current state of the application. - - ``` handlebars - {{outlet}} - ``` - - By default, a template based on Ember's naming conventions will be rendered - into the `outlet` (e.g. `App.PostsRoute` will render the `posts` template). - - You can render a different template by using the `render()` method in the - route's `renderTemplate` hook. The following will render the `favoritePost` - template into the `outlet`. - - ``` javascript - App.PostsRoute = Ember.Route.extend({ - renderTemplate: function() { - this.render('favoritePost'); - } - }); - ``` - - You can create custom named outlets for more control. - - ``` handlebars - {{outlet 'favoritePost'}} - {{outlet 'posts'}} - ``` - - Then you can define what template is rendered into each outlet in your - route. - - - ``` javascript - App.PostsRoute = Ember.Route.extend({ - renderTemplate: function() { - this.render('favoritePost', { outlet: 'favoritePost' }); - this.render('posts', { outlet: 'posts' }); - } - }); - ``` - - You can specify the view that the outlet uses to contain and manage the - templates rendered into it. - - ``` handlebars - {{outlet view='sectionContainer'}} - ``` - - ``` javascript - App.SectionContainer = Ember.ContainerView.extend({ - tagName: 'section', - classNames: ['special'] - }); - ``` - - @method outlet - @for Ember.Handlebars.helpers - @param {String} property the property on the controller - that holds the view for this outlet - @return {String} HTML string - */ - function outletHelper(params, hash, options, env) { - var outletSource; - var viewName; - var viewClass; - var viewFullName; - - Ember.assert( - "Using {{outlet}} with an unquoted name is not supported.", - params.length === 0 || typeof params[0] === 'string' - ); - - var property = params[0] || 'main'; - - outletSource = this; - while (!outletSource.get('template.isTop')) { - outletSource = outletSource.get('_parentView'); - } - set(this, 'outletSource', outletSource); - - // provide controller override - viewName = hash.view; - - if (viewName) { - viewFullName = 'view:' + viewName; - Ember.assert( - "Using a quoteless view parameter with {{outlet}} is not supported." + - " Please update to quoted usage '{{outlet ... view=\"" + viewName + "\"}}.", - typeof hash.view === 'string' - ); - Ember.assert( - "The view name you supplied '" + viewName + "' did not resolve to a view.", - this.container.has(viewFullName) - ); - } - - viewClass = viewName ? this.container.lookupFactory(viewFullName) : hash.viewClass || OutletView; - - hash.currentViewBinding = '_view.outletSource._outlets.' + property; - - options.helperName = options.helperName || 'outlet'; - - return env.helpers.view.helperFunction.call(this, [viewClass], hash, options, env); - } - - __exports__.outletHelper = outletHelper; - }); -enifed("ember-routing-htmlbars/helpers/query-params", - ["ember-metal/core","ember-routing/system/query_params","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-routing-htmlbars - */ - - var Ember = __dependency1__["default"]; - // assert - var QueryParams = __dependency2__["default"]; - - /** - This is a sub-expression to be used in conjunction with the link-to helper. - It will supply url query parameters to the target route. - - Example - - {{#link-to 'posts' (query-params direction="asc")}}Sort{{/link-to}} - - @method query-params - @for Ember.Handlebars.helpers - @param {Object} hash takes a hash of query parameters - @return {String} HTML string - */ - function queryParamsHelper(params, hash) { - Ember.assert("The `query-params` helper only accepts hash parameters, e.g. (query-params queryParamPropertyName='foo') as opposed to just (query-params 'foo')", params.length === 0); - - return QueryParams.create({ - values: hash - }); - } - - __exports__.queryParamsHelper = queryParamsHelper; - }); -enifed("ember-routing-htmlbars/helpers/render", - ["ember-metal/core","ember-metal/error","ember-runtime/system/string","ember-routing/system/generate_controller","ember-htmlbars/helpers/view","ember-metal/streams/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-routing-htmlbars - */ - - var Ember = __dependency1__["default"]; - // assert, deprecate - var EmberError = __dependency2__["default"]; - var camelize = __dependency3__.camelize; - var generateControllerFactory = __dependency4__.generateControllerFactory; - var generateController = __dependency4__["default"]; - var ViewHelper = __dependency5__.ViewHelper; - var isStream = __dependency6__.isStream; - - /** - Calling ``{{render}}`` from within a template will insert another - template that matches the provided name. The inserted template will - access its properties on its own controller (rather than the controller - of the parent template). - - If a view class with the same name exists, the view class also will be used. - - Note: A given controller may only be used *once* in your app in this manner. - A singleton instance of the controller will be created for you. - - Example: - - ```javascript - App.NavigationController = Ember.Controller.extend({ - who: "world" - }); - ``` - - ```handlebars - - Hello, {{who}}. - ``` - - ```handlebars - -

    My great app

    - {{render "navigation"}} - ``` - - ```html -

    My great app

    -
    - Hello, world. -
    - ``` - - Optionally you may provide a second argument: a property path - that will be bound to the `model` property of the controller. - - If a `model` property path is specified, then a new instance of the - controller will be created and `{{render}}` can be used multiple times - with the same name. - - For example if you had this `author` template. - - ```handlebars -
    - Written by {{firstName}} {{lastName}}. - Total Posts: {{postCount}} -
    - ``` - - You could render it inside the `post` template using the `render` helper. - - ```handlebars -
    -

    {{title}}

    -
    {{body}}
    - {{render "author" author}} -
    - ``` - - @method render - @for Ember.Handlebars.helpers - @param {String} name - @param {Object?} context - @param {Hash} options - @return {String} HTML string - */ - function renderHelper(params, hash, options, env) { - var container, router, controller, view, initialContext; - - var name = params[0]; - var context = params[1]; - - container = this._keywords.controller.value().container; - router = container.lookup('router:main'); - - Ember.assert( - "The first argument of {{render}} must be quoted, e.g. {{render \"sidebar\"}}.", - typeof name === 'string' - ); - - Ember.assert( - "The second argument of {{render}} must be a path, e.g. {{render \"post\" post}}.", - params.length < 2 || isStream(params[1]) - ); - - - if (params.length === 1) { - // use the singleton controller - Ember.assert("You can only use the {{render}} helper once without a model object as its" + - " second argument, as in {{render \"post\" post}}.", !router || !router._lookupActiveView(name)); - } else if (params.length === 2) { - // create a new controller - initialContext = context.value(); - } else { - throw new EmberError("You must pass a templateName to render"); - } - - // # legacy namespace - name = name.replace(/\//g, '.'); - // \ legacy slash as namespace support - - - view = container.lookup('view:' + name) || container.lookup('view:default'); - - // provide controller override - var controllerName = hash.controller || name; - var controllerFullName = 'controller:' + controllerName; - - Ember.assert("The controller name you supplied '" + controllerName + - "' did not resolve to a controller.", !hash.controller || container.has(controllerFullName)); - - var parentController = this._keywords.controller.value(); - - // choose name - if (params.length > 1) { - var factory = container.lookupFactory(controllerFullName) || - generateControllerFactory(container, controllerName, initialContext); - - controller = factory.create({ - modelBinding: context, // TODO: Use a StreamBinding - parentController: parentController, - target: parentController - }); - - view.one('willDestroyElement', function() { - controller.destroy(); - }); - } else { - controller = container.lookup(controllerFullName) || - generateController(container, controllerName); - - controller.setProperties({ - target: parentController, - parentController: parentController - }); - } - - hash.viewName = camelize(name); - - var templateName = 'template:' + name; - Ember.assert("You used `{{render '" + name + "'}}`, but '" + name + "' can not be found as either" + - " a template or a view.", container.has("view:" + name) || container.has(templateName) || !!options.template); - hash.template = container.lookup(templateName); - - hash.controller = controller; - - if (router && !initialContext) { - router._connectActiveView(name, view); - } - - options.helperName = options.helperName || ('render "' + name + '"'); - - ViewHelper.instanceHelper(view, hash, options, env); - } - - __exports__.renderHelper = renderHelper; - }); -enifed("ember-routing-views", - ["ember-metal/core","ember-routing-views/views/link","ember-routing-views/views/outlet","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - /** - Ember Routing Views - - @module ember - @submodule ember-routing-views - @requires ember-routing - */ - - var Ember = __dependency1__["default"]; - - var LinkView = __dependency2__.LinkView; - var OutletView = __dependency3__.OutletView; - - Ember.LinkView = LinkView; - Ember.OutletView = OutletView; - - __exports__["default"] = Ember; - }); -enifed("ember-routing-views/views/link", - ["ember-metal/core","ember-metal/property_get","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-runtime/system/string","ember-metal/keys","ember-views/system/utils","ember-views/views/component","ember-routing/utils","ember-metal/streams/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-routing-views - */ - - var Ember = __dependency1__["default"]; - // FEATURES, Logger, assert - - var get = __dependency2__.get; - var merge = __dependency3__["default"]; - var run = __dependency4__["default"]; - var computed = __dependency5__.computed; - var fmt = __dependency6__.fmt; - var keys = __dependency7__["default"]; - var isSimpleClick = __dependency8__.isSimpleClick; - var EmberComponent = __dependency9__["default"]; - var routeArgs = __dependency10__.routeArgs; - var read = __dependency11__.read; - var subscribe = __dependency11__.subscribe; - - var numberOfContextsAcceptedByHandler = function(handler, handlerInfos) { - var req = 0; - for (var i = 0, l = handlerInfos.length; i < l; i++) { - req = req + handlerInfos[i].names.length; - if (handlerInfos[i].handler === handler) - break; - } - - return req; - }; - - /** - `Ember.LinkView` renders an element whose `click` event triggers a - transition of the application's instance of `Ember.Router` to - a supplied route by name. - - Instances of `LinkView` will most likely be created through - the `link-to` Handlebars helper, but properties of this class - can be overridden to customize application-wide behavior. - - @class LinkView - @namespace Ember - @extends Ember.View - @see {Handlebars.helpers.link-to} - **/ - var LinkView = Ember.LinkView = EmberComponent.extend({ - tagName: 'a', - - /** - @deprecated Use current-when instead. - @property currentWhen - */ - currentWhen: null, - - /** - Used to determine when this LinkView is active. - - @property currentWhen - */ - 'current-when': null, - - /** - Sets the `title` attribute of the `LinkView`'s HTML element. - - @property title - @default null - **/ - title: null, - - /** - Sets the `rel` attribute of the `LinkView`'s HTML element. - - @property rel - @default null - **/ - rel: null, - - /** - Sets the `tabindex` attribute of the `LinkView`'s HTML element. - - @property tabindex - @default null - **/ - tabindex: null, - - /** - Sets the `target` attribute of the `LinkView`'s HTML element. - - @since 1.8.0 - @property target - @default null - **/ - target: null, - - /** - The CSS class to apply to `LinkView`'s element when its `active` - property is `true`. - - @property activeClass - @type String - @default active - **/ - activeClass: 'active', - - /** - The CSS class to apply to `LinkView`'s element when its `loading` - property is `true`. - - @property loadingClass - @type String - @default loading - **/ - loadingClass: 'loading', - - /** - The CSS class to apply to a `LinkView`'s element when its `disabled` - property is `true`. - - @property disabledClass - @type String - @default disabled - **/ - disabledClass: 'disabled', - _isDisabled: false, - - /** - Determines whether the `LinkView` will trigger routing via - the `replaceWith` routing strategy. - - @property replace - @type Boolean - @default false - **/ - replace: false, - - /** - By default the `{{link-to}}` helper will bind to the `href` and - `title` attributes. It's discouraged that you override these defaults, - however you can push onto the array if needed. - - @property attributeBindings - @type Array | String - @default ['href', 'title', 'rel', 'tabindex', 'target'] - **/ - attributeBindings: ['href', 'title', 'rel', 'tabindex'], - - /** - By default the `{{link-to}}` helper will bind to the `active`, `loading`, and - `disabled` classes. It is discouraged to override these directly. - - @property classNameBindings - @type Array - @default ['active', 'loading', 'disabled'] - **/ - classNameBindings: ['active', 'loading', 'disabled'], - - /** - By default the `{{link-to}}` helper responds to the `click` event. You - can override this globally by setting this property to your custom - event name. - - This is particularly useful on mobile when one wants to avoid the 300ms - click delay using some sort of custom `tap` event. - - @property eventName - @type String - @default click - */ - eventName: 'click', - - // this is doc'ed here so it shows up in the events - // section of the API documentation, which is where - // people will likely go looking for it. - /** - Triggers the `LinkView`'s routing behavior. If - `eventName` is changed to a value other than `click` - the routing behavior will trigger on that custom event - instead. - - @event click - **/ - - /** - An overridable method called when LinkView objects are instantiated. - - Example: - - ```javascript - App.MyLinkView = Ember.LinkView.extend({ - init: function() { - this._super(); - Ember.Logger.log('Event is ' + this.get('eventName')); - } - }); - ``` - - NOTE: If you do override `init` for a framework class like `Ember.View` or - `Ember.ArrayController`, be sure to call `this._super()` in your - `init` declaration! If you don't, Ember may not have an opportunity to - do important setup work, and you'll see strange behavior in your - application. - - @method init - */ - init: function() { - this._super.apply(this, arguments); - - Ember.deprecate('Using currentWhen with {{link-to}} is deprecated in favor of `current-when`.', !this.currentWhen); - - // Map desired event name to invoke function - var eventName = get(this, 'eventName'); - this.on(eventName, this, this._invoke); - }, - - /** - This method is invoked by observers installed during `init` that fire - whenever the params change - - @private - @method _paramsChanged - @since 1.3.0 - */ - _paramsChanged: function() { - this.notifyPropertyChange('resolvedParams'); - }, - - /** - This is called to setup observers that will trigger a rerender. - - @private - @method _setupPathObservers - @since 1.3.0 - **/ - _setupPathObservers: function(){ - var params = this.params; - - var scheduledRerender = this._wrapAsScheduled(this.rerender); - var scheduledParamsChanged = this._wrapAsScheduled(this._paramsChanged); - - if (this.linkTitle) { - var linkTitle = this.linkTitle.stream || this.linkTitle; - subscribe(linkTitle, scheduledRerender, this); - } - - for (var i = 0; i < params.length; i++) { - subscribe(params[i], scheduledParamsChanged, this); - } - - var queryParamsObject = this.queryParamsObject; - if (queryParamsObject) { - var values = queryParamsObject.values; - for (var k in values) { - if (!values.hasOwnProperty(k)) { - continue; - } - - subscribe(values[k], scheduledParamsChanged, this); - } - } - }, - - afterRender: function(){ - this._super.apply(this, arguments); - this._setupPathObservers(); - }, - - /** - - Accessed as a classname binding to apply the `LinkView`'s `disabledClass` - CSS `class` to the element when the link is disabled. - - When `true` interactions with the element will not trigger route changes. - @property disabled - */ - disabled: computed(function computeLinkViewDisabled(key, value) { - if (value !== undefined) { this.set('_isDisabled', value); } - - return value ? get(this, 'disabledClass') : false; - }), - - /** - Accessed as a classname binding to apply the `LinkView`'s `activeClass` - CSS `class` to the element when the link is active. - - A `LinkView` is considered active when its `currentWhen` property is `true` - or the application's current route is the route the `LinkView` would trigger - transitions into. - - The `currentWhen` property can match against multiple routes by separating - route names using the ` ` (space) character. - - @property active - **/ - active: computed('loadedParams', function computeLinkViewActive() { - if (get(this, 'loading')) { return false; } - - var router = get(this, 'router'); - var loadedParams = get(this, 'loadedParams'); - var contexts = loadedParams.models; - var currentWhen = this['current-when'] || this.currentWhen; - var isCurrentWhenSpecified = Boolean(currentWhen); - currentWhen = currentWhen || loadedParams.targetRouteName; - - function isActiveForRoute(routeName) { - var handlers = router.router.recognizer.handlersFor(routeName); - var leafName = handlers[handlers.length-1].handler; - var maximumContexts = numberOfContextsAcceptedByHandler(routeName, handlers); - - // NOTE: any ugliness in the calculation of activeness is largely - // due to the fact that we support automatic normalizing of - // `resource` -> `resource.index`, even though there might be - // dynamic segments / query params defined on `resource.index` - // which complicates (and makes somewhat ambiguous) the calculation - // of activeness for links that link to `resource` instead of - // directly to `resource.index`. - - // if we don't have enough contexts revert back to full route name - // this is because the leaf route will use one of the contexts - if (contexts.length > maximumContexts) { - routeName = leafName; - } - - var args = routeArgs(routeName, contexts, null); - var isActive = router.isActive.apply(router, args); - if (!isActive) { return false; } - - var emptyQueryParams = Ember.isEmpty(Ember.keys(loadedParams.queryParams)); - - if (!isCurrentWhenSpecified && !emptyQueryParams && isActive) { - var visibleQueryParams = {}; - merge(visibleQueryParams, loadedParams.queryParams); - router._prepareQueryParams(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); - isActive = shallowEqual(visibleQueryParams, router.router.state.queryParams); - } - - return isActive; - } - - - currentWhen = currentWhen.split(' '); - for (var i = 0, len = currentWhen.length; i < len; i++) { - if (isActiveForRoute(currentWhen[i])) { - return get(this, 'activeClass'); - } - } - }), - - /** - Accessed as a classname binding to apply the `LinkView`'s `loadingClass` - CSS `class` to the element when the link is loading. - - A `LinkView` is considered loading when it has at least one - parameter whose value is currently null or undefined. During - this time, clicking the link will perform no transition and - emit a warning that the link is still in a loading state. - - @property loading - **/ - loading: computed('loadedParams', function computeLinkViewLoading() { - if (!get(this, 'loadedParams')) { return get(this, 'loadingClass'); } - }), - - /** - Returns the application's main router from the container. - - @private - @property router - **/ - router: computed(function() { - var controller = get(this, 'controller'); - if (controller && controller.container) { - return controller.container.lookup('router:main'); - } - }), - - /** - Event handler that invokes the link, activating the associated route. - - @private - @method _invoke - @param {Event} event - */ - _invoke: function(event) { - if (!isSimpleClick(event)) { return true; } - - if (this.preventDefault !== false) { - - var targetAttribute = get(this, 'target'); - if (!targetAttribute || targetAttribute === '_self') { - event.preventDefault(); - } - } - - if (this.bubbles === false) { event.stopPropagation(); } - - if (get(this, '_isDisabled')) { return false; } - - if (get(this, 'loading')) { - Ember.Logger.warn("This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid."); - return false; - } - - - var targetAttribute2 = get(this, 'target'); - if (targetAttribute2 && targetAttribute2 !== '_self') { - return false; - } - - - var router = get(this, 'router'); - var loadedParams = get(this, 'loadedParams'); - - var transition = router._doTransition(loadedParams.targetRouteName, loadedParams.models, loadedParams.queryParams); - if (get(this, 'replace')) { - transition.method('replace'); - } - - // Schedule eager URL update, but after we've given the transition - // a chance to synchronously redirect. - // We need to always generate the URL instead of using the href because - // the href will include any rootURL set, but the router expects a URL - // without it! Note that we don't use the first level router because it - // calls location.formatURL(), which also would add the rootURL! - var args = routeArgs(loadedParams.targetRouteName, loadedParams.models, transition.state.queryParams); - var url = router.router.generate.apply(router.router, args); - - run.scheduleOnce('routerTransitions', this, this._eagerUpdateUrl, transition, url); - }, - - /** - @private - @method _eagerUpdateUrl - @param transition - @param href - */ - _eagerUpdateUrl: function(transition, href) { - if (!transition.isActive || !transition.urlMethod) { - // transition was aborted, already ran to completion, - // or it has a null url-updated method. - return; - } - - if (href.indexOf('#') === 0) { - href = href.slice(1); - } - - // Re-use the routerjs hooks set up by the Ember router. - var routerjs = get(this, 'router.router'); - if (transition.urlMethod === 'update') { - routerjs.updateURL(href); - } else if (transition.urlMethod === 'replace') { - routerjs.replaceURL(href); - } - - // Prevent later update url refire. - transition.method(null); - }, - - /** - Computed property that returns an array of the - resolved parameters passed to the `link-to` helper, - e.g.: - - ```hbs - {{link-to a b '123' c}} - ``` - - will generate a `resolvedParams` of: - - ```js - [aObject, bObject, '123', cObject] - ``` - - @private - @property - @return {Array} - */ - resolvedParams: computed('router.url', function() { - var params = this.params; - var targetRouteName; - var models = []; - var onlyQueryParamsSupplied = (params.length === 0); - - if (onlyQueryParamsSupplied) { - var appController = this.container.lookup('controller:application'); - targetRouteName = get(appController, 'currentRouteName'); - } else { - targetRouteName = read(params[0]); - - for (var i = 1; i < params.length; i++) { - models.push(read(params[i])); - } - } - - var suppliedQueryParams = getResolvedQueryParams(this, targetRouteName); - - return { - targetRouteName: targetRouteName, - models: models, - queryParams: suppliedQueryParams - }; - }), - - /** - Computed property that returns the current route name, - dynamic segments, and query params. Returns falsy if - for null/undefined params to indicate that the link view - is still in a loading state. - - @private - @property - @return {Array} An array with the route name and any dynamic segments - **/ - loadedParams: computed('resolvedParams', function computeLinkViewRouteArgs() { - var router = get(this, 'router'); - if (!router) { return; } - - var resolvedParams = get(this, 'resolvedParams'); - var namedRoute = resolvedParams.targetRouteName; - - if (!namedRoute) { return; } - - Ember.assert(fmt("The attempt to link-to route '%@' failed. " + - "The router did not find '%@' in its possible routes: '%@'", - [namedRoute, namedRoute, keys(router.router.recognizer.names).join("', '")]), - router.hasRoute(namedRoute)); - - if (!paramsAreLoaded(resolvedParams.models)) { return; } - - return resolvedParams; - }), - - queryParamsObject: null, - - /** - Sets the element's `href` attribute to the url for - the `LinkView`'s targeted route. - - If the `LinkView`'s `tagName` is changed to a value other - than `a`, this property will be ignored. - - @property href - **/ - href: computed('loadedParams', function computeLinkViewHref() { - if (get(this, 'tagName') !== 'a') { return; } - - var router = get(this, 'router'); - var loadedParams = get(this, 'loadedParams'); - - if (!loadedParams) { - return get(this, 'loadingHref'); - } - - var visibleQueryParams = {}; - merge(visibleQueryParams, loadedParams.queryParams); - router._prepareQueryParams(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); - - var args = routeArgs(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); - var result = router.generate.apply(router, args); - return result; - }), - - /** - The default href value to use while a link-to is loading. - Only applies when tagName is 'a' - - @property loadingHref - @type String - @default # - */ - loadingHref: '#' - }); - - LinkView.toString = function() { return "LinkView"; }; - - - LinkView.reopen({ - attributeBindings: ['target'], - - /** - Sets the `target` attribute of the `LinkView`'s anchor element. - - @property target - @default null - **/ - target: null - }); - - - function getResolvedQueryParams(linkView, targetRouteName) { - var queryParamsObject = linkView.queryParamsObject; - var resolvedQueryParams = {}; - - if (!queryParamsObject) { return resolvedQueryParams; } - - var values = queryParamsObject.values; - for (var key in values) { - if (!values.hasOwnProperty(key)) { continue; } - resolvedQueryParams[key] = read(values[key]); - } - - return resolvedQueryParams; - } - - function paramsAreLoaded(params) { - for (var i = 0, len = params.length; i < len; ++i) { - var param = params[i]; - if (param === null || typeof param === 'undefined') { - return false; - } - } - return true; - } - - function shallowEqual(a, b) { - var k; - for (k in a) { - if (a.hasOwnProperty(k) && a[k] !== b[k]) { return false; } - } - for (k in b) { - if (b.hasOwnProperty(k) && a[k] !== b[k]) { return false; } - } - return true; - } - - __exports__.LinkView = LinkView; - }); -enifed("ember-routing-views/views/outlet", - ["ember-views/views/container_view","ember-views/views/metamorph_view","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-routing-views - */ - - var ContainerView = __dependency1__["default"]; - var _Metamorph = __dependency2__._Metamorph; - - var OutletView = ContainerView.extend(_Metamorph); - __exports__.OutletView = OutletView; - }); -enifed("ember-routing", - ["ember-metal/core","ember-routing/ext/run_loop","ember-routing/ext/controller","ember-routing/ext/view","ember-routing/location/api","ember-routing/location/none_location","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/system/generate_controller","ember-routing/system/controller_for","ember-routing/system/dsl","ember-routing/system/router","ember-routing/system/route","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __exports__) { - "use strict"; - /** - Ember Routing - - @module ember - @submodule ember-routing - @requires ember-views - */ - - var Ember = __dependency1__["default"]; - - // ES6TODO: Cleanup modules with side-effects below - - var EmberLocation = __dependency5__["default"]; - var NoneLocation = __dependency6__["default"]; - var HashLocation = __dependency7__["default"]; - var HistoryLocation = __dependency8__["default"]; - var AutoLocation = __dependency9__["default"]; - - var generateControllerFactory = __dependency10__.generateControllerFactory; - var generateController = __dependency10__["default"]; - var controllerFor = __dependency11__["default"]; - var RouterDSL = __dependency12__["default"]; - var Router = __dependency13__["default"]; - var Route = __dependency14__["default"]; - - Ember.Location = EmberLocation; - Ember.AutoLocation = AutoLocation; - Ember.HashLocation = HashLocation; - Ember.HistoryLocation = HistoryLocation; - Ember.NoneLocation = NoneLocation; - - Ember.controllerFor = controllerFor; - Ember.generateControllerFactory = generateControllerFactory; - Ember.generateController = generateController; - Ember.RouterDSL = RouterDSL; - Ember.Router = Router; - Ember.Route = Route; - - __exports__["default"] = Ember; - }); -enifed("ember-routing/ext/controller", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/merge","ember-runtime/mixins/controller","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // FEATURES, deprecate - var get = __dependency2__.get; - var set = __dependency3__.set; - var computed = __dependency4__.computed; - var typeOf = __dependency5__.typeOf; - var meta = __dependency5__.meta; - var merge = __dependency6__["default"]; - - var ControllerMixin = __dependency7__["default"]; - - /** - @module ember - @submodule ember-routing - */ - - ControllerMixin.reopen({ - concatenatedProperties: ['queryParams', '_pCacheMeta'], - - init: function() { - this._super.apply(this, arguments); - listenForQueryParamChanges(this); - }, - - /** - Defines which query parameters the controller accepts. - If you give the names ['category','page'] it will bind - the values of these query parameters to the variables - `this.category` and `this.page` - - @property queryParams - @public - */ - queryParams: null, - - /** - @property _qpDelegate - @private - */ - _qpDelegate: null, - - /** - @property _normalizedQueryParams - @private - */ - _normalizedQueryParams: computed(function() { - var m = meta(this); - if (m.proto !== this) { - return get(m.proto, '_normalizedQueryParams'); - } - - var queryParams = get(this, 'queryParams'); - if (queryParams._qpMap) { - return queryParams._qpMap; - } - - var qpMap = queryParams._qpMap = {}; - - for (var i = 0, len = queryParams.length; i < len; ++i) { - accumulateQueryParamDescriptors(queryParams[i], qpMap); - } - - return qpMap; - }), - - /** - @property _cacheMeta - @private - */ - _cacheMeta: computed(function() { - var m = meta(this); - if (m.proto !== this) { - return get(m.proto, '_cacheMeta'); - } - - var cacheMeta = {}; - var qpMap = get(this, '_normalizedQueryParams'); - for (var prop in qpMap) { - if (!qpMap.hasOwnProperty(prop)) { continue; } - - var qp = qpMap[prop]; - var scope = qp.scope; - var parts; - - if (scope === 'controller') { - parts = []; - } - - cacheMeta[prop] = { - parts: parts, // provided by route if 'model' scope - values: null, // provided by route - scope: scope, - prefix: "", - def: get(this, prop) - }; - } - - return cacheMeta; - }), - - /** - @method _updateCacheParams - @private - */ - _updateCacheParams: function(params) { - var cacheMeta = get(this, '_cacheMeta'); - for (var prop in cacheMeta) { - if (!cacheMeta.hasOwnProperty(prop)) { continue; } - var propMeta = cacheMeta[prop]; - propMeta.values = params; - - var cacheKey = this._calculateCacheKey(propMeta.prefix, propMeta.parts, propMeta.values); - var cache = this._bucketCache; - - if (cache) { - var value = cache.lookup(cacheKey, prop, propMeta.def); - set(this, prop, value); - } - } - }, - - /** - @method _qpChanged - @private - */ - _qpChanged: function(controller, _prop) { - var prop = _prop.substr(0, _prop.length-3); - var cacheMeta = get(controller, '_cacheMeta'); - var propCache = cacheMeta[prop]; - var cacheKey = controller._calculateCacheKey(propCache.prefix || "", propCache.parts, propCache.values); - var value = get(controller, prop); - - // 1. Update model-dep cache - var cache = this._bucketCache; - if (cache) { - controller._bucketCache.stash(cacheKey, prop, value); - } - - // 2. Notify a delegate (e.g. to fire a qp transition) - var delegate = controller._qpDelegate; - if (delegate) { - delegate(controller, prop); - } - }, - - /** - @method _calculateCacheKey - @private - */ - _calculateCacheKey: function(prefix, _parts, values) { - var parts = _parts || [], suffixes = ""; - for (var i = 0, len = parts.length; i < len; ++i) { - var part = parts[i]; - var value = get(values, part); - suffixes += "::" + part + ":" + value; - } - return prefix + suffixes.replace(ALL_PERIODS_REGEX, '-'); - }, - - /** - Transition the application into another route. The route may - be either a single route or route path: - - ```javascript - aController.transitionToRoute('blogPosts'); - aController.transitionToRoute('blogPosts.recentEntries'); - ``` - - Optionally supply a model for the route in question. The model - will be serialized into the URL using the `serialize` hook of - the route: - - ```javascript - aController.transitionToRoute('blogPost', aPost); - ``` - - If a literal is passed (such as a number or a string), it will - be treated as an identifier instead. In this case, the `model` - hook of the route will be triggered: - - ```javascript - aController.transitionToRoute('blogPost', 1); - ``` - - Multiple models will be applied last to first recursively up the - resource tree. - - ```javascript - App.Router.map(function() { - this.resource('blogPost', {path:':blogPostId'}, function(){ - this.resource('blogComment', {path: ':blogCommentId'}); - }); - }); - - aController.transitionToRoute('blogComment', aPost, aComment); - aController.transitionToRoute('blogComment', 1, 13); - ``` - - It is also possible to pass a URL (a string that starts with a - `/`). This is intended for testing and debugging purposes and - should rarely be used in production code. - - ```javascript - aController.transitionToRoute('/'); - aController.transitionToRoute('/blog/post/1/comment/13'); - aController.transitionToRoute('/blog/posts?sort=title'); - ``` - - An options hash with a `queryParams` property may be provided as - the final argument to add query parameters to the destination URL. - - ```javascript - aController.transitionToRoute('blogPost', 1, { - queryParams: {showComments: 'true'} - }); - - // if you just want to transition the query parameters without changing the route - aController.transitionToRoute({queryParams: {sort: 'date'}}); - ``` - - See also [replaceRoute](/api/classes/Ember.ControllerMixin.html#method_replaceRoute). - - @param {String} name the name of the route or a URL - @param {...Object} models the model(s) or identifier(s) to be used - while transitioning to the route. - @param {Object} [options] optional hash with a queryParams property - containing a mapping of query parameters - @for Ember.ControllerMixin - @method transitionToRoute - */ - transitionToRoute: function() { - // target may be either another controller or a router - var target = get(this, 'target'); - var method = target.transitionToRoute || target.transitionTo; - return method.apply(target, arguments); - }, - - /** - @deprecated - @for Ember.ControllerMixin - @method transitionTo - */ - transitionTo: function() { - Ember.deprecate("transitionTo is deprecated. Please use transitionToRoute."); - return this.transitionToRoute.apply(this, arguments); - }, - - /** - Transition into another route while replacing the current URL, if possible. - This will replace the current history entry instead of adding a new one. - Beside that, it is identical to `transitionToRoute` in all other respects. - - ```javascript - aController.replaceRoute('blogPosts'); - aController.replaceRoute('blogPosts.recentEntries'); - ``` - - Optionally supply a model for the route in question. The model - will be serialized into the URL using the `serialize` hook of - the route: - - ```javascript - aController.replaceRoute('blogPost', aPost); - ``` - - If a literal is passed (such as a number or a string), it will - be treated as an identifier instead. In this case, the `model` - hook of the route will be triggered: - - ```javascript - aController.replaceRoute('blogPost', 1); - ``` - - Multiple models will be applied last to first recursively up the - resource tree. - - ```javascript - App.Router.map(function() { - this.resource('blogPost', {path:':blogPostId'}, function(){ - this.resource('blogComment', {path: ':blogCommentId'}); - }); - }); - - aController.replaceRoute('blogComment', aPost, aComment); - aController.replaceRoute('blogComment', 1, 13); - ``` - - It is also possible to pass a URL (a string that starts with a - `/`). This is intended for testing and debugging purposes and - should rarely be used in production code. - - ```javascript - aController.replaceRoute('/'); - aController.replaceRoute('/blog/post/1/comment/13'); - ``` - - @param {String} name the name of the route or a URL - @param {...Object} models the model(s) or identifier(s) to be used - while transitioning to the route. - @for Ember.ControllerMixin - @method replaceRoute - */ - replaceRoute: function() { - // target may be either another controller or a router - var target = get(this, 'target'); - var method = target.replaceRoute || target.replaceWith; - return method.apply(target, arguments); - }, - - /** - @deprecated - @for Ember.ControllerMixin - @method replaceWith - */ - replaceWith: function() { - Ember.deprecate("replaceWith is deprecated. Please use replaceRoute."); - return this.replaceRoute.apply(this, arguments); - } - }); - - var ALL_PERIODS_REGEX = /\./g; - - function accumulateQueryParamDescriptors(_desc, accum) { - var desc = _desc; - var tmp; - if (typeOf(desc) === 'string') { - tmp = {}; - tmp[desc] = { as: null }; - desc = tmp; - } - - for (var key in desc) { - if (!desc.hasOwnProperty(key)) { return; } - - var singleDesc = desc[key]; - if (typeOf(singleDesc) === 'string') { - singleDesc = { as: singleDesc }; - } - - tmp = accum[key] || { as: null, scope: 'model' }; - merge(tmp, singleDesc); - - accum[key] = tmp; - } - } - - function listenForQueryParamChanges(controller) { - var qpMap = get(controller, '_normalizedQueryParams'); - for (var prop in qpMap) { - if (!qpMap.hasOwnProperty(prop)) { continue; } - controller.addObserver(prop + '.[]', controller, controller._qpChanged); - } - } - - - __exports__["default"] = ControllerMixin; - }); -enifed("ember-routing/ext/run_loop", - ["ember-metal/run_loop"], - function(__dependency1__) { - "use strict"; - var run = __dependency1__["default"]; - - /** - @module ember - @submodule ember-views - */ - - // Add a new named queue after the 'actions' queue (where RSVP promises - // resolve), which is used in router transitions to prevent unnecessary - // loading state entry if all context promises resolve on the - // 'actions' queue first. - run._addQueue('routerTransitions', 'actions'); - }); -enifed("ember-routing/ext/view", - ["ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-views/views/view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var get = __dependency1__.get; - var set = __dependency2__.set; - var run = __dependency3__["default"]; - var EmberView = __dependency4__["default"]; - - /** - @module ember - @submodule ember-routing - */ - - EmberView.reopen({ - - /** - Sets the private `_outlets` object on the view. - - @method init - */ - init: function() { - this._outlets = {}; - this._super(); - }, - - /** - Manually fill any of a view's `{{outlet}}` areas with the - supplied view. - - Example - - ```javascript - var MyView = Ember.View.extend({ - template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') - }); - var myView = MyView.create(); - myView.appendTo('body'); - // The html for myView now looks like: - //
    Child view:
    - - var FooView = Ember.View.extend({ - template: Ember.Handlebars.compile('

    Foo

    ') - }); - var fooView = FooView.create(); - myView.connectOutlet('main', fooView); - // The html for myView now looks like: - //
    Child view: - //

    Foo

    - //
    - ``` - @method connectOutlet - @param {String} outletName A unique name for the outlet - @param {Object} view An Ember.View - */ - connectOutlet: function(outletName, view) { - if (this._pendingDisconnections) { - delete this._pendingDisconnections[outletName]; - } - - if (this._hasEquivalentView(outletName, view)) { - view.destroy(); - return; - } - - var outlets = get(this, '_outlets'); - var container = get(this, 'container'); - var router = container && container.lookup('router:main'); - var renderedName = get(view, 'renderedName'); - - set(outlets, outletName, view); - - if (router && renderedName) { - router._connectActiveView(renderedName, view); - } - }, - - /** - Determines if the view has already been created by checking if - the view has the same constructor, template, and context as the - view in the `_outlets` object. - - @private - @method _hasEquivalentView - @param {String} outletName The name of the outlet we are checking - @param {Object} view An Ember.View - @return {Boolean} - */ - _hasEquivalentView: function(outletName, view) { - var existingView = get(this, '_outlets.'+outletName); - return existingView && - existingView.constructor === view.constructor && - existingView.get('template') === view.get('template') && - existingView.get('context') === view.get('context'); - }, - - /** - Removes an outlet from the view. - - Example - - ```javascript - var MyView = Ember.View.extend({ - template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') - }); - var myView = MyView.create(); - myView.appendTo('body'); - // myView's html: - //
    Child view:
    - - var FooView = Ember.View.extend({ - template: Ember.Handlebars.compile('

    Foo

    ') - }); - var fooView = FooView.create(); - myView.connectOutlet('main', fooView); - // myView's html: - //
    Child view: - //

    Foo

    - //
    - - myView.disconnectOutlet('main'); - // myView's html: - //
    Child view:
    - ``` - - @method disconnectOutlet - @param {String} outletName The name of the outlet to be removed - */ - disconnectOutlet: function(outletName) { - if (!this._pendingDisconnections) { - this._pendingDisconnections = {}; - } - this._pendingDisconnections[outletName] = true; - run.once(this, '_finishDisconnections'); - }, - - /** - Gets an outlet that is pending disconnection and then - nullifys the object on the `_outlet` object. - - @private - @method _finishDisconnections - */ - _finishDisconnections: function() { - if (this.isDestroyed) return; // _outlets will be gone anyway - var outlets = get(this, '_outlets'); - var pendingDisconnections = this._pendingDisconnections; - this._pendingDisconnections = null; - - for (var outletName in pendingDisconnections) { - set(outlets, outletName, null); - } - } - }); - - __exports__["default"] = EmberView; - }); -enifed("ember-routing/location/api", - ["ember-metal/core","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // deprecate, assert - - /** - @module ember - @submodule ember-routing - */ - - /** - Ember.Location returns an instance of the correct implementation of - the `location` API. - - ## Implementations - - You can pass an implementation name (`hash`, `history`, `none`) to force a - particular implementation to be used in your application. - - ### HashLocation - - Using `HashLocation` results in URLs with a `#` (hash sign) separating the - server side URL portion of the URL from the portion that is used by Ember. - This relies upon the `hashchange` event existing in the browser. - - Example: - - ```javascript - App.Router.map(function() { - this.resource('posts', function() { - this.route('new'); - }); - }); - - App.Router.reopen({ - location: 'hash' - }); - ``` - - This will result in a posts.new url of `/#/posts/new`. - - ### HistoryLocation - - Using `HistoryLocation` results in URLs that are indistinguishable from a - standard URL. This relies upon the browser's `history` API. - - Example: - - ```javascript - App.Router.map(function() { - this.resource('posts', function() { - this.route('new'); - }); - }); - - App.Router.reopen({ - location: 'history' - }); - ``` - - This will result in a posts.new url of `/posts/new`. - - Keep in mind that your server must serve the Ember app at all the routes you - define. - - ### AutoLocation - - Using `AutoLocation`, the router will use the best Location class supported by - the browser it is running in. - - Browsers that support the `history` API will use `HistoryLocation`, those that - do not, but still support the `hashchange` event will use `HashLocation`, and - in the rare case neither is supported will use `NoneLocation`. - - Example: - - ```javascript - App.Router.map(function() { - this.resource('posts', function() { - this.route('new'); - }); - }); - - App.Router.reopen({ - location: 'auto' - }); - ``` - - This will result in a posts.new url of `/posts/new` for modern browsers that - support the `history` api or `/#/posts/new` for older ones, like Internet - Explorer 9 and below. - - When a user visits a link to your application, they will be automatically - upgraded or downgraded to the appropriate `Location` class, with the URL - transformed accordingly, if needed. - - Keep in mind that since some of your users will use `HistoryLocation`, your - server must serve the Ember app at all the routes you define. - - ### NoneLocation - - Using `NoneLocation` causes Ember to not store the applications URL state - in the actual URL. This is generally used for testing purposes, and is one - of the changes made when calling `App.setupForTesting()`. - - ## Location API - - Each location implementation must provide the following methods: - - * implementation: returns the string name used to reference the implementation. - * getURL: returns the current URL. - * setURL(path): sets the current URL. - * replaceURL(path): replace the current URL (optional). - * onUpdateURL(callback): triggers the callback when the URL changes. - * formatURL(url): formats `url` to be placed into `href` attribute. - - Calling setURL or replaceURL will not trigger onUpdateURL callbacks. - - @class Location - @namespace Ember - @static - */ - __exports__["default"] = { - /** - This is deprecated in favor of using the container to lookup the location - implementation as desired. - - For example: - - ```javascript - // Given a location registered as follows: - container.register('location:history-test', HistoryTestLocation); - - // You could create a new instance via: - container.lookup('location:history-test'); - ``` - - @method create - @param {Object} options - @return {Object} an instance of an implementation of the `location` API - @deprecated Use the container to lookup the location implementation that you - need. - */ - create: function(options) { - var implementation = options && options.implementation; - Ember.assert("Ember.Location.create: you must specify a 'implementation' option", !!implementation); - - var implementationClass = this.implementations[implementation]; - Ember.assert("Ember.Location.create: " + implementation + " is not a valid implementation", !!implementationClass); - - return implementationClass.create.apply(implementationClass, arguments); - }, - - /** - This is deprecated in favor of using the container to register the - location implementation as desired. - - Example: - - ```javascript - Application.initializer({ - name: "history-test-location", - - initialize: function(container, application) { - application.register('location:history-test', HistoryTestLocation); - } - }); - ``` - - @method registerImplementation - @param {String} name - @param {Object} implementation of the `location` API - @deprecated Register your custom location implementation with the - container directly. - */ - registerImplementation: function(name, implementation) { - Ember.deprecate('Using the Ember.Location.registerImplementation is no longer supported.' + - ' Register your custom location implementation with the container instead.', false); - - this.implementations[name] = implementation; - }, - - implementations: {}, - _location: window.location, - - /** - Returns the current `location.hash` by parsing location.href since browsers - inconsistently URL-decode `location.hash`. - - https://bugzilla.mozilla.org/show_bug.cgi?id=483304 - - @private - @method getHash - @since 1.4.0 - */ - _getHash: function () { - // AutoLocation has it at _location, HashLocation at .location. - // Being nice and not changing - var href = (this._location || this.location).href; - var hashIndex = href.indexOf('#'); - - if (hashIndex === -1) { - return ''; - } else { - return href.substr(hashIndex); - } - } - }; - }); -enifed("ember-routing/location/auto_location", - ["ember-metal/core","ember-metal/property_set","ember-routing/location/api","ember-routing/location/history_location","ember-routing/location/hash_location","ember-routing/location/none_location","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // FEATURES - var set = __dependency2__.set; - - var EmberLocation = __dependency3__["default"]; - var HistoryLocation = __dependency4__["default"]; - var HashLocation = __dependency5__["default"]; - var NoneLocation = __dependency6__["default"]; - - /** - @module ember - @submodule ember-routing - */ - - /** - Ember.AutoLocation will select the best location option based off browser - support with the priority order: history, hash, none. - - Clean pushState paths accessed by hashchange-only browsers will be redirected - to the hash-equivalent and vice versa so future transitions are consistent. - - Keep in mind that since some of your users will use `HistoryLocation`, your - server must serve the Ember app at all the routes you define. - - @class AutoLocation - @namespace Ember - @static - */ - __exports__["default"] = { - - /** - @private - - This property is used by router:main to know whether to cancel the routing - setup process, which is needed while we redirect the browser. - - @since 1.5.1 - @property cancelRouterSetup - @default false - */ - cancelRouterSetup: false, - - /** - @private - - Will be pre-pended to path upon state change. - - @since 1.5.1 - @property rootURL - @default '/' - */ - rootURL: '/', - - /** - @private - - Attached for mocking in tests - - @since 1.5.1 - @property _window - @default window - */ - _window: window, - - /** - @private - - Attached for mocking in tests - - @property location - @default window.location - */ - _location: window.location, - - /** - @private - - Attached for mocking in tests - - @since 1.5.1 - @property _history - @default window.history - */ - _history: window.history, - - /** - @private - - Attached for mocking in tests - - @since 1.5.1 - @property _HistoryLocation - @default Ember.HistoryLocation - */ - _HistoryLocation: HistoryLocation, - - /** - @private - - Attached for mocking in tests - - @since 1.5.1 - @property _HashLocation - @default Ember.HashLocation - */ - _HashLocation: HashLocation, - - /** - @private - - Attached for mocking in tests - - @since 1.5.1 - @property _NoneLocation - @default Ember.NoneLocation - */ - _NoneLocation: NoneLocation, - - /** - @private - - Returns location.origin or builds it if device doesn't support it. - - @method _getOrigin - */ - _getOrigin: function () { - var location = this._location; - var origin = location.origin; - - // Older browsers, especially IE, don't have origin - if (!origin) { - origin = location.protocol + '//' + location.hostname; - - if (location.port) { - origin += ':' + location.port; - } - } - - return origin; - }, - - /** - @private - - We assume that if the history object has a pushState method, the host should - support HistoryLocation. - - @method _getSupportsHistory - */ - _getSupportsHistory: function () { - // Boosted from Modernizr: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js - // The stock browser on Android 2.2 & 2.3 returns positive on history support - // Unfortunately support is really buggy and there is no clean way to detect - // these bugs, so we fall back to a user agent sniff :( - var userAgent = this._window.navigator.userAgent; - - // We only want Android 2, stock browser, and not Chrome which identifies - // itself as 'Mobile Safari' as well - if (userAgent.indexOf('Android 2') !== -1 && - userAgent.indexOf('Mobile Safari') !== -1 && - userAgent.indexOf('Chrome') === -1) { - return false; - } - - return !!(this._history && 'pushState' in this._history); - }, - - /** - @private - - IE8 running in IE7 compatibility mode gives false positive, so we must also - check documentMode. - - @method _getSupportsHashChange - */ - _getSupportsHashChange: function () { - var _window = this._window; - var documentMode = _window.document.documentMode; - - return ('onhashchange' in _window && (documentMode === undefined || documentMode > 7 )); - }, - - /** - @private - - Redirects the browser using location.replace, prepending the locatin.origin - to prevent phishing attempts - - @method _replacePath - */ - _replacePath: function (path) { - this._location.replace(this._getOrigin() + path); - }, - - /** - @since 1.5.1 - @private - @method _getRootURL - */ - _getRootURL: function () { - return this.rootURL; - }, - - /** - @private - - Returns the current `location.pathname`, normalized for IE inconsistencies. - - @method _getPath - */ - _getPath: function () { - var pathname = this._location.pathname; - // Various versions of IE/Opera don't always return a leading slash - if (pathname.charAt(0) !== '/') { - pathname = '/' + pathname; - } - - return pathname; - }, - - /** - @private - - Returns normalized location.hash as an alias to Ember.Location._getHash - - @since 1.5.1 - @method _getHash - */ - _getHash: EmberLocation._getHash, - - /** - @private - - Returns location.search - - @since 1.5.1 - @method _getQuery - */ - _getQuery: function () { - return this._location.search; - }, - - /** - @private - - Returns the full pathname including query and hash - - @method _getFullPath - */ - _getFullPath: function () { - return this._getPath() + this._getQuery() + this._getHash(); - }, - - /** - @private - - Returns the current path as it should appear for HistoryLocation supported - browsers. This may very well differ from the real current path (e.g. if it - starts off as a hashed URL) - - @method _getHistoryPath - */ - _getHistoryPath: function () { - var rootURL = this._getRootURL(); - var path = this._getPath(); - var hash = this._getHash(); - var query = this._getQuery(); - var rootURLIndex = path.indexOf(rootURL); - var routeHash, hashParts; - - Ember.assert('Path ' + path + ' does not start with the provided rootURL ' + rootURL, rootURLIndex === 0); - - // By convention, Ember.js routes using HashLocation are required to start - // with `#/`. Anything else should NOT be considered a route and should - // be passed straight through, without transformation. - if (hash.substr(0, 2) === '#/') { - // There could be extra hash segments after the route - hashParts = hash.substr(1).split('#'); - // The first one is always the route url - routeHash = hashParts.shift(); - - // If the path already has a trailing slash, remove the one - // from the hashed route so we don't double up. - if (path.slice(-1) === '/') { - routeHash = routeHash.substr(1); - } - - // This is the "expected" final order - path += routeHash; - path += query; - - if (hashParts.length) { - path += '#' + hashParts.join('#'); - } - } else { - path += query; - path += hash; - } - - return path; - }, - - /** - @private - - Returns the current path as it should appear for HashLocation supported - browsers. This may very well differ from the real current path. - - @method _getHashPath - */ - _getHashPath: function () { - var rootURL = this._getRootURL(); - var path = rootURL; - var historyPath = this._getHistoryPath(); - var routePath = historyPath.substr(rootURL.length); - - if (routePath !== '') { - if (routePath.charAt(0) !== '/') { - routePath = '/' + routePath; - } - - path += '#' + routePath; - } - - return path; - }, - - /** - Selects the best location option based off browser support and returns an - instance of that Location class. - - @see Ember.AutoLocation - @method create - */ - create: function (options) { - if (options && options.rootURL) { - Ember.assert('rootURL must end with a trailing forward slash e.g. "/app/"', - options.rootURL.charAt(options.rootURL.length-1) === '/'); - this.rootURL = options.rootURL; - } - - var historyPath, hashPath; - var cancelRouterSetup = false; - var implementationClass = this._NoneLocation; - var currentPath = this._getFullPath(); - - if (this._getSupportsHistory()) { - historyPath = this._getHistoryPath(); - - // Since we support history paths, let's be sure we're using them else - // switch the location over to it. - if (currentPath === historyPath) { - implementationClass = this._HistoryLocation; - } else { - - if (currentPath.substr(0, 2) === '/#') { - this._history.replaceState({ path: historyPath }, null, historyPath); - implementationClass = this._HistoryLocation; - } else { - cancelRouterSetup = true; - this._replacePath(historyPath); - } - } - - } else if (this._getSupportsHashChange()) { - hashPath = this._getHashPath(); - - // Be sure we're using a hashed path, otherwise let's switch over it to so - // we start off clean and consistent. We'll count an index path with no - // hash as "good enough" as well. - if (currentPath === hashPath || (currentPath === '/' && hashPath === '/#/')) { - implementationClass = this._HashLocation; - } else { - // Our URL isn't in the expected hash-supported format, so we want to - // cancel the router setup and replace the URL to start off clean - cancelRouterSetup = true; - this._replacePath(hashPath); - } - } - - var implementation = implementationClass.create.apply(implementationClass, arguments); - - if (cancelRouterSetup) { - set(implementation, 'cancelRouterSetup', true); - } - - return implementation; - } - }; - }); -enifed("ember-routing/location/hash_location", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/object","ember-routing/location/api","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var get = __dependency2__.get; - var set = __dependency3__.set; - var run = __dependency4__["default"]; - var guidFor = __dependency5__.guidFor; - - var EmberObject = __dependency6__["default"]; - var EmberLocation = __dependency7__["default"]; - - /** - @module ember - @submodule ember-routing - */ - - /** - `Ember.HashLocation` implements the location API using the browser's - hash. At present, it relies on a `hashchange` event existing in the - browser. - - @class HashLocation - @namespace Ember - @extends Ember.Object - */ - __exports__["default"] = EmberObject.extend({ - implementation: 'hash', - - init: function() { - set(this, 'location', get(this, '_location') || window.location); - }, - - /** - @private - - Returns normalized location.hash - - @since 1.5.1 - @method getHash - */ - getHash: EmberLocation._getHash, - - /** - Returns the normalized URL, constructed from `location.hash`. - - e.g. `#/foo` => `/foo` as well as `#/foo#bar` => `/foo#bar`. - - By convention, hashed paths must begin with a forward slash, otherwise they - are not treated as a path so we can distinguish intent. - - @private - @method getURL - */ - getURL: function() { - var originalPath = this.getHash().substr(1); - var outPath = originalPath; - - if (outPath.charAt(0) !== '/') { - outPath = '/'; - - // Only add the # if the path isn't empty. - // We do NOT want `/#` since the ampersand - // is only included (conventionally) when - // the location.hash has a value - if (originalPath) { - outPath += '#' + originalPath; - } - } - - return outPath; - }, - - /** - Set the `location.hash` and remembers what was set. This prevents - `onUpdateURL` callbacks from triggering when the hash was set by - `HashLocation`. - - @private - @method setURL - @param path {String} - */ - setURL: function(path) { - get(this, 'location').hash = path; - set(this, 'lastSetURL', path); - }, - - /** - Uses location.replace to update the url without a page reload - or history modification. - - @private - @method replaceURL - @param path {String} - */ - replaceURL: function(path) { - get(this, 'location').replace('#' + path); - set(this, 'lastSetURL', path); - }, - - /** - Register a callback to be invoked when the hash changes. These - callbacks will execute when the user presses the back or forward - button, but not after `setURL` is invoked. - - @private - @method onUpdateURL - @param callback {Function} - */ - onUpdateURL: function(callback) { - var self = this; - var guid = guidFor(this); - - Ember.$(window).on('hashchange.ember-location-'+guid, function() { - run(function() { - var path = self.getURL(); - if (get(self, 'lastSetURL') === path) { return; } - - set(self, 'lastSetURL', null); - - callback(path); - }); - }); - }, - - /** - Given a URL, formats it to be placed into the page as part - of an element's `href` attribute. - - This is used, for example, when using the {{action}} helper - to generate a URL based on an event. - - @private - @method formatURL - @param url {String} - */ - formatURL: function(url) { - return '#' + url; - }, - - /** - Cleans up the HashLocation event listener. - - @private - @method willDestroy - */ - willDestroy: function() { - var guid = guidFor(this); - - Ember.$(window).off('hashchange.ember-location-'+guid); - } - }); - }); -enifed("ember-routing/location/history_location", - ["ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-runtime/system/object","ember-routing/location/api","ember-views/system/jquery","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - var get = __dependency1__.get; - var set = __dependency2__.set; - var guidFor = __dependency3__.guidFor; - - var EmberObject = __dependency4__["default"]; - var EmberLocation = __dependency5__["default"]; - var jQuery = __dependency6__["default"]; - - /** - @module ember - @submodule ember-routing - */ - - var popstateFired = false; - var supportsHistoryState = window.history && 'state' in window.history; - - /** - Ember.HistoryLocation implements the location API using the browser's - history.pushState API. - - @class HistoryLocation - @namespace Ember - @extends Ember.Object - */ - __exports__["default"] = EmberObject.extend({ - implementation: 'history', - - init: function() { - set(this, 'location', get(this, 'location') || window.location); - set(this, 'baseURL', jQuery('base').attr('href') || ''); - }, - - /** - Used to set state on first call to setURL - - @private - @method initState - */ - initState: function() { - set(this, 'history', get(this, 'history') || window.history); - this.replaceState(this.formatURL(this.getURL())); - }, - - /** - Will be pre-pended to path upon state change - - @property rootURL - @default '/' - */ - rootURL: '/', - - /** - Returns the current `location.pathname` without `rootURL` or `baseURL` - - @private - @method getURL - @return url {String} - */ - getURL: function() { - var rootURL = get(this, 'rootURL'); - var location = get(this, 'location'); - var path = location.pathname; - var baseURL = get(this, 'baseURL'); - - rootURL = rootURL.replace(/\/$/, ''); - baseURL = baseURL.replace(/\/$/, ''); - - var url = path.replace(baseURL, '').replace(rootURL, ''); - var search = location.search || ''; - - url += search; - url += this.getHash(); - - return url; - }, - - /** - Uses `history.pushState` to update the url without a page reload. - - @private - @method setURL - @param path {String} - */ - setURL: function(path) { - var state = this.getState(); - path = this.formatURL(path); - - if (!state || state.path !== path) { - this.pushState(path); - } - }, - - /** - Uses `history.replaceState` to update the url without a page reload - or history modification. - - @private - @method replaceURL - @param path {String} - */ - replaceURL: function(path) { - var state = this.getState(); - path = this.formatURL(path); - - if (!state || state.path !== path) { - this.replaceState(path); - } - }, - - /** - Get the current `history.state`. Checks for if a polyfill is - required and if so fetches this._historyState. The state returned - from getState may be null if an iframe has changed a window's - history. - - @private - @method getState - @return state {Object} - */ - getState: function() { - return supportsHistoryState ? get(this, 'history').state : this._historyState; - }, - - /** - Pushes a new state. - - @private - @method pushState - @param path {String} - */ - pushState: function(path) { - var state = { path: path }; - - get(this, 'history').pushState(state, null, path); - - // store state if browser doesn't support `history.state` - if (!supportsHistoryState) { - this._historyState = state; - } - - // used for webkit workaround - this._previousURL = this.getURL(); - }, - - /** - Replaces the current state. - - @private - @method replaceState - @param path {String} - */ - replaceState: function(path) { - var state = { path: path }; - get(this, 'history').replaceState(state, null, path); - - // store state if browser doesn't support `history.state` - if (!supportsHistoryState) { - this._historyState = state; - } - - // used for webkit workaround - this._previousURL = this.getURL(); - }, - - /** - Register a callback to be invoked whenever the browser - history changes, including using forward and back buttons. - - @private - @method onUpdateURL - @param callback {Function} - */ - onUpdateURL: function(callback) { - var guid = guidFor(this); - var self = this; - - jQuery(window).on('popstate.ember-location-'+guid, function(e) { - // Ignore initial page load popstate event in Chrome - if (!popstateFired) { - popstateFired = true; - if (self.getURL() === self._previousURL) { return; } - } - callback(self.getURL()); - }); - }, - - /** - Used when using `{{action}}` helper. The url is always appended to the rootURL. - - @private - @method formatURL - @param url {String} - @return formatted url {String} - */ - formatURL: function(url) { - var rootURL = get(this, 'rootURL'); - var baseURL = get(this, 'baseURL'); - - if (url !== '') { - rootURL = rootURL.replace(/\/$/, ''); - baseURL = baseURL.replace(/\/$/, ''); - } else if(baseURL.match(/^\//) && rootURL.match(/^\//)) { - baseURL = baseURL.replace(/\/$/, ''); - } - - return baseURL + rootURL + url; - }, - - /** - Cleans up the HistoryLocation event listener. - - @private - @method willDestroy - */ - willDestroy: function() { - var guid = guidFor(this); - - jQuery(window).off('popstate.ember-location-'+guid); - }, - - /** - @private - - Returns normalized location.hash - - @method getHash - */ - getHash: EmberLocation._getHash - }); - }); -enifed("ember-routing/location/none_location", - ["ember-metal/property_get","ember-metal/property_set","ember-runtime/system/object","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var get = __dependency1__.get; - var set = __dependency2__.set; - var EmberObject = __dependency3__["default"]; - - /** - @module ember - @submodule ember-routing - */ - - /** - Ember.NoneLocation does not interact with the browser. It is useful for - testing, or when you need to manage state with your Router, but temporarily - don't want it to muck with the URL (for example when you embed your - application in a larger page). - - @class NoneLocation - @namespace Ember - @extends Ember.Object - */ - __exports__["default"] = EmberObject.extend({ - implementation: 'none', - path: '', - - /** - Returns the current path. - - @private - @method getURL - @return {String} path - */ - getURL: function() { - return get(this, 'path'); - }, - - /** - Set the path and remembers what was set. Using this method - to change the path will not invoke the `updateURL` callback. - - @private - @method setURL - @param path {String} - */ - setURL: function(path) { - set(this, 'path', path); - }, - - /** - Register a callback to be invoked when the path changes. These - callbacks will execute when the user presses the back or forward - button, but not after `setURL` is invoked. - - @private - @method onUpdateURL - @param callback {Function} - */ - onUpdateURL: function(callback) { - this.updateCallback = callback; - }, - - /** - Sets the path and calls the `updateURL` callback. - - @private - @method handleURL - @param callback {Function} - */ - handleURL: function(url) { - set(this, 'path', url); - this.updateCallback(url); - }, - - /** - Given a URL, formats it to be placed into the page as part - of an element's `href` attribute. - - This is used, for example, when using the {{action}} helper - to generate a URL based on an event. - - @private - @method formatURL - @param url {String} - @return {String} url - */ - formatURL: function(url) { - // The return value is not overly meaningful, but we do not want to throw - // errors when test code renders templates containing {{action href=true}} - // helpers. - return url; - } - }); - }); -enifed("ember-routing/system/cache", - ["ember-runtime/system/object","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var EmberObject = __dependency1__["default"]; - - __exports__["default"] = EmberObject.extend({ - init: function() { - this.cache = {}; - }, - has: function(bucketKey) { - return bucketKey in this.cache; - }, - stash: function(bucketKey, key, value) { - var bucket = this.cache[bucketKey]; - if (!bucket) { - bucket = this.cache[bucketKey] = {}; - } - bucket[key] = value; - }, - lookup: function(bucketKey, prop, defaultValue) { - var cache = this.cache; - if (!(bucketKey in cache)) { - return defaultValue; - } - var bucket = cache[bucketKey]; - if (prop in bucket) { - return bucket[prop]; - } else { - return defaultValue; - } - }, - cache: null - }); - }); -enifed("ember-routing/system/controller_for", - ["exports"], - function(__exports__) { - "use strict"; - /** - @module ember - @submodule ember-routing - */ - - /** - - Finds a controller instance. - - @for Ember - @method controllerFor - @private - */ - __exports__["default"] = function controllerFor(container, controllerName, lookupOptions) { - return container.lookup('controller:' + controllerName, lookupOptions); - } - }); -enifed("ember-routing/system/dsl", - ["ember-metal/core","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // FEATURES, assert - - /** - @module ember - @submodule ember-routing - */ - - function DSL(name) { - this.parent = name; - this.matches = []; - } - __exports__["default"] = DSL; - - DSL.prototype = { - route: function(name, options, callback) { - if (arguments.length === 2 && typeof options === 'function') { - callback = options; - options = {}; - } - - if (arguments.length === 1) { - options = {}; - } - - var type = options.resetNamespace === true ? 'resource' : 'route'; - Ember.assert("'basic' cannot be used as a " + type + " name.", name !== 'basic'); - - - if (callback) { - var fullName = getFullName(this, name, options.resetNamespace); - var dsl = new DSL(fullName); - createRoute(dsl, 'loading'); - createRoute(dsl, 'error', { path: "/_unused_dummy_error_path_route_" + name + "/:error" }); - - callback.call(dsl); - - createRoute(this, name, options, dsl.generate()); - } else { - createRoute(this, name, options); - } - }, - - push: function(url, name, callback) { - var parts = name.split('.'); - if (url === "" || url === "/" || parts[parts.length-1] === "index") { this.explicitIndex = true; } - - this.matches.push([url, name, callback]); - }, - - resource: function(name, options, callback) { - if (arguments.length === 2 && typeof options === 'function') { - callback = options; - options = {}; - } - - if (arguments.length === 1) { - options = {}; - } - - options.resetNamespace = true; - this.route(name, options, callback); - }, - - generate: function() { - var dslMatches = this.matches; - - if (!this.explicitIndex) { - this.route("index", { path: "/" }); - } - - return function(match) { - for (var i=0, l=dslMatches.length; i " + fullName, { fullName: fullName }); - } - - return instance; - } - }); -enifed("ember-routing/system/query_params", - ["ember-runtime/system/object","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var EmberObject = __dependency1__["default"]; - - __exports__["default"] = EmberObject.extend({ - isQueryParams: true, - values: null - }); - }); -enifed("ember-routing/system/route", - ["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/get_properties","ember-metal/enumerable_utils","ember-metal/is_none","ember-metal/computed","ember-metal/merge","ember-metal/utils","ember-metal/run_loop","ember-metal/keys","ember-runtime/copy","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/mixins/evented","ember-runtime/mixins/action_handler","ember-routing/system/generate_controller","ember-routing/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // FEATURES, A, deprecate, assert, Logger - var EmberError = __dependency2__["default"]; - var get = __dependency3__.get; - var set = __dependency4__.set; - var getProperties = __dependency5__["default"]; - var forEach = __dependency6__.forEach; - var replace = __dependency6__.replace; - var isNone = __dependency7__["default"]; - var computed = __dependency8__.computed; - var merge = __dependency9__["default"]; - var isArray = __dependency10__.isArray; - var typeOf = __dependency10__.typeOf; - var run = __dependency11__["default"]; - var keys = __dependency12__["default"]; - var copy = __dependency13__["default"]; - var classify = __dependency14__.classify; - var EmberObject = __dependency15__["default"]; - var Evented = __dependency16__["default"]; - var ActionHandler = __dependency17__["default"]; - var generateController = __dependency18__["default"]; - var stashParamNames = __dependency19__.stashParamNames; - - var slice = Array.prototype.slice; - - function K() { return this; } - - /** - @module ember - @submodule ember-routing - */ - - /** - The `Ember.Route` class is used to define individual routes. Refer to - the [routing guide](http://emberjs.com/guides/routing/) for documentation. - - @class Route - @namespace Ember - @extends Ember.Object - @uses Ember.ActionHandler - */ - var Route = EmberObject.extend(ActionHandler, { - /** - Configuration hash for this route's queryParams. The possible - configuration options and their defaults are as follows - (assuming a query param whose URL key is `page`): - - ```javascript - queryParams: { - page: { - // By default, controller query param properties don't - // cause a full transition when they are changed, but - // rather only cause the URL to update. Setting - // `refreshModel` to true will cause an "in-place" - // transition to occur, whereby the model hooks for - // this route (and any child routes) will re-fire, allowing - // you to reload models (e.g., from the server) using the - // updated query param values. - refreshModel: false, - - // By default, changes to controller query param properties - // cause the URL to update via `pushState`, which means an - // item will be added to the browser's history, allowing - // you to use the back button to restore the app to the - // previous state before the query param property was changed. - // Setting `replace` to true will use `replaceState` (or its - // hash location equivalent), which causes no browser history - // item to be added. This options name and default value are - // the same as the `link-to` helper's `replace` option. - replace: false - } - } - ``` - - @property queryParams - @for Ember.Route - @type Hash - */ - queryParams: {}, - - /** - @private - - @property _qp - */ - _qp: computed(function() { - var controllerName = this.controllerName || this.routeName; - var controllerClass = this.container.lookupFactory('controller:' + controllerName); - - if (!controllerClass) { - return defaultQPMeta; - } - - var controllerProto = controllerClass.proto(); - var qpProps = get(controllerProto, '_normalizedQueryParams'); - var cacheMeta = get(controllerProto, '_cacheMeta'); - - var qps = [], map = {}, self = this; - for (var propName in qpProps) { - if (!qpProps.hasOwnProperty(propName)) { continue; } - - var desc = qpProps[propName]; - var urlKey = desc.as || this.serializeQueryParamKey(propName); - var defaultValue = get(controllerProto, propName); - - if (isArray(defaultValue)) { - defaultValue = Ember.A(defaultValue.slice()); - } - - var type = typeOf(defaultValue); - var defaultValueSerialized = this.serializeQueryParam(defaultValue, urlKey, type); - var fprop = controllerName + ':' + propName; - var qp = { - def: defaultValue, - sdef: defaultValueSerialized, - type: type, - urlKey: urlKey, - prop: propName, - fprop: fprop, - ctrl: controllerName, - cProto: controllerProto, - svalue: defaultValueSerialized, - cacheType: desc.scope, - route: this, - cacheMeta: cacheMeta[propName] - }; - - map[propName] = map[urlKey] = map[fprop] = qp; - qps.push(qp); - } - - return { - qps: qps, - map: map, - states: { - active: function(controller, prop) { - return self._activeQPChanged(controller, map[prop]); - }, - allowOverrides: function(controller, prop) { - return self._updatingQPChanged(controller, map[prop]); - }, - changingKeys: function(controller, prop) { - return self._updateSerializedQPValue(controller, map[prop]); - } - } - }; - }), - - /** - @private - - @property _names - */ - _names: null, - - /** - @private - - @method _stashNames - */ - _stashNames: function(_handlerInfo, dynamicParent) { - var handlerInfo = _handlerInfo; - if (this._names) { return; } - var names = this._names = handlerInfo._names; - - if (!names.length) { - handlerInfo = dynamicParent; - names = handlerInfo && handlerInfo._names || []; - } - - var qps = get(this, '_qp.qps'); - var len = qps.length; - - var namePaths = new Array(names.length); - for (var a = 0, nlen = names.length; a < nlen; ++a) { - namePaths[a] = handlerInfo.name + '.' + names[a]; - } - - for (var i = 0; i < len; ++i) { - var qp = qps[i]; - var cacheMeta = qp.cacheMeta; - if (cacheMeta.scope === 'model') { - cacheMeta.parts = namePaths; - } - cacheMeta.prefix = qp.ctrl; - } - }, - - /** - @private - - @property _updateSerializedQPValue - */ - _updateSerializedQPValue: function(controller, qp) { - var value = get(controller, qp.prop); - qp.svalue = this.serializeQueryParam(value, qp.urlKey, qp.type); - }, - - /** - @private - - @property _activeQPChanged - */ - _activeQPChanged: function(controller, qp) { - var value = get(controller, qp.prop); - this.router._queuedQPChanges[qp.fprop] = value; - run.once(this, this._fireQueryParamTransition); - }, - - /** - @private - @method _updatingQPChanged - */ - _updatingQPChanged: function(controller, qp) { - var router = this.router; - if (!router._qpUpdates) { - router._qpUpdates = {}; - } - router._qpUpdates[qp.urlKey] = true; - }, - - mergedProperties: ['events', 'queryParams'], - - /** - Retrieves parameters, for current route using the state.params - variable and getQueryParamsFor, using the supplied routeName. - - @method paramsFor - @param {String} routename - - */ - paramsFor: function(name) { - var route = this.container.lookup('route:' + name); - - if (!route) { - return {}; - } - - var transition = this.router.router.activeTransition; - var state = transition ? transition.state : this.router.router.state; - - var params = {}; - merge(params, state.params[name]); - merge(params, getQueryParamsFor(route, state)); - - return params; - }, - - /** - Serializes the query parameter key - - @method serializeQueryParamKey - @param {String} controllerPropertyName - */ - serializeQueryParamKey: function(controllerPropertyName) { - return controllerPropertyName; - }, - - /** - Serializes value of the query parameter based on defaultValueType - - @method serializeQueryParam - @param {Object} value - @param {String} urlKey - @param {String} defaultValueType - */ - serializeQueryParam: function(value, urlKey, defaultValueType) { - // urlKey isn't used here, but anyone overriding - // can use it to provide serialization specific - // to a certain query param. - if (defaultValueType === 'array') { - return JSON.stringify(value); - } - return '' + value; - }, - - /** - Deserializes value of the query parameter based on defaultValueType - - @method deserializeQueryParam - @param {Object} value - @param {String} urlKey - @param {String} defaultValueType - */ - deserializeQueryParam: function(value, urlKey, defaultValueType) { - // urlKey isn't used here, but anyone overriding - // can use it to provide deserialization specific - // to a certain query param. - - // Use the defaultValueType of the default value (the initial value assigned to a - // controller query param property), to intelligently deserialize and cast. - if (defaultValueType === 'boolean') { - return (value === 'true') ? true : false; - } else if (defaultValueType === 'number') { - return (Number(value)).valueOf(); - } else if (defaultValueType === 'array') { - return Ember.A(JSON.parse(value)); - } - return value; - }, - - - /** - @private - @property _fireQueryParamTransition - */ - _fireQueryParamTransition: function() { - this.transitionTo({ queryParams: this.router._queuedQPChanges }); - this.router._queuedQPChanges = {}; - }, - - /** - @private - - @property _optionsForQueryParam - */ - _optionsForQueryParam: function(qp) { - return get(this, 'queryParams.' + qp.urlKey) || get(this, 'queryParams.' + qp.prop) || {}; - }, - - /** - A hook you can use to reset controller values either when the model - changes or the route is exiting. - - ```javascript - App.ArticlesRoute = Ember.Route.extend({ - // ... - - resetController: function (controller, isExiting, transition) { - if (isExiting) { - controller.set('page', 1); - } - } - }); - ``` - - @method resetController - @param {Controller} controller instance - @param {Boolean} isExiting - @param {Object} transition - @since 1.7.0 - */ - resetController: K, - - /** - @private - - @method exit - */ - exit: function() { - this.deactivate(); - - this.trigger('deactivate'); - - this.teardownViews(); - }, - - /** - @private - - @method _reset - @since 1.7.0 - */ - _reset: function(isExiting, transition) { - var controller = this.controller; - - controller._qpDelegate = get(this, '_qp.states.inactive'); - - this.resetController(controller, isExiting, transition); - }, - - /** - @private - - @method enter - */ - enter: function() { - this.activate(); - - this.trigger('activate'); - - }, - - /** - The name of the view to use by default when rendering this routes template. - - When rendering a template, the route will, by default, determine the - template and view to use from the name of the route itself. If you need to - define a specific view, set this property. - - This is useful when multiple routes would benefit from using the same view - because it doesn't require a custom `renderTemplate` method. For example, - the following routes will all render using the `App.PostsListView` view: - - ```javascript - var PostsList = Ember.Route.extend({ - viewName: 'postsList' - }); - - App.PostsIndexRoute = PostsList.extend(); - App.PostsArchivedRoute = PostsList.extend(); - ``` - - @property viewName - @type String - @default null - @since 1.4.0 - */ - viewName: null, - - /** - The name of the template to use by default when rendering this routes - template. - - This is similar with `viewName`, but is useful when you just want a custom - template without a view. - - ```javascript - var PostsList = Ember.Route.extend({ - templateName: 'posts/list' - }); - - App.PostsIndexRoute = PostsList.extend(); - App.PostsArchivedRoute = PostsList.extend(); - ``` - - @property templateName - @type String - @default null - @since 1.4.0 - */ - templateName: null, - - /** - The name of the controller to associate with this route. - - By default, Ember will lookup a route's controller that matches the name - of the route (i.e. `App.PostController` for `App.PostRoute`). However, - if you would like to define a specific controller to use, you can do so - using this property. - - This is useful in many ways, as the controller specified will be: - - * passed to the `setupController` method. - * used as the controller for the view being rendered by the route. - * returned from a call to `controllerFor` for the route. - - @property controllerName - @type String - @default null - @since 1.4.0 - */ - controllerName: null, - - /** - The `willTransition` action is fired at the beginning of any - attempted transition with a `Transition` object as the sole - argument. This action can be used for aborting, redirecting, - or decorating the transition from the currently active routes. - - A good example is preventing navigation when a form is - half-filled out: - - ```javascript - App.ContactFormRoute = Ember.Route.extend({ - actions: { - willTransition: function(transition) { - if (this.controller.get('userHasEnteredData')) { - this.controller.displayNavigationConfirm(); - transition.abort(); - } - } - } - }); - ``` - - You can also redirect elsewhere by calling - `this.transitionTo('elsewhere')` from within `willTransition`. - Note that `willTransition` will not be fired for the - redirecting `transitionTo`, since `willTransition` doesn't - fire when there is already a transition underway. If you want - subsequent `willTransition` actions to fire for the redirecting - transition, you must first explicitly call - `transition.abort()`. - - @event willTransition - @param {Transition} transition - */ - - /** - The `didTransition` action is fired after a transition has - successfully been completed. This occurs after the normal model - hooks (`beforeModel`, `model`, `afterModel`, `setupController`) - have resolved. The `didTransition` action has no arguments, - however, it can be useful for tracking page views or resetting - state on the controller. - - ```javascript - App.LoginRoute = Ember.Route.extend({ - actions: { - didTransition: function() { - this.controller.get('errors.base').clear(); - return true; // Bubble the didTransition event - } - } - }); - ``` - - @event didTransition - @since 1.2.0 - */ - - /** - The `loading` action is fired on the route when a route's `model` - hook returns a promise that is not already resolved. The current - `Transition` object is the first parameter and the route that - triggered the loading event is the second parameter. - - ```javascript - App.ApplicationRoute = Ember.Route.extend({ - actions: { - loading: function(transition, route) { - var view = Ember.View.create({ - classNames: ['app-loading'] - }) - .append(); - - this.router.one('didTransition', function() { - view.destroy(); - }); - - return true; // Bubble the loading event - } - } - }); - ``` - - @event loading - @param {Transition} transition - @param {Ember.Route} route The route that triggered the loading event - @since 1.2.0 - */ - - /** - When attempting to transition into a route, any of the hooks - may return a promise that rejects, at which point an `error` - action will be fired on the partially-entered routes, allowing - for per-route error handling logic, or shared error handling - logic defined on a parent route. - - Here is an example of an error handler that will be invoked - for rejected promises from the various hooks on the route, - as well as any unhandled errors from child routes: - - ```javascript - App.AdminRoute = Ember.Route.extend({ - beforeModel: function() { - return Ember.RSVP.reject('bad things!'); - }, - - actions: { - error: function(error, transition) { - // Assuming we got here due to the error in `beforeModel`, - // we can expect that error === "bad things!", - // but a promise model rejecting would also - // call this hook, as would any errors encountered - // in `afterModel`. - - // The `error` hook is also provided the failed - // `transition`, which can be stored and later - // `.retry()`d if desired. - - this.transitionTo('login'); - } - } - }); - ``` - - `error` actions that bubble up all the way to `ApplicationRoute` - will fire a default error handler that logs the error. You can - specify your own global default error handler by overriding the - `error` handler on `ApplicationRoute`: - - ```javascript - App.ApplicationRoute = Ember.Route.extend({ - actions: { - error: function(error, transition) { - this.controllerFor('banner').displayError(error.message); - } - } - }); - ``` - @event error - @param {Error} error - @param {Transition} transition - */ - - /** - The controller associated with this route. - - Example - - ```javascript - App.FormRoute = Ember.Route.extend({ - actions: { - willTransition: function(transition) { - if (this.controller.get('userHasEnteredData') && - !confirm('Are you sure you want to abandon progress?')) { - transition.abort(); - } else { - // Bubble the `willTransition` action so that - // parent routes can decide whether or not to abort. - return true; - } - } - } - }); - ``` - - @property controller - @type Ember.Controller - @since 1.6.0 - */ - - _actions: { - - queryParamsDidChange: function(changed, totalPresent, removed) { - var qpMap = get(this, '_qp').map; - - var totalChanged = keys(changed).concat(keys(removed)); - for (var i = 0, len = totalChanged.length; i < len; ++i) { - var qp = qpMap[totalChanged[i]]; - if (qp && get(this._optionsForQueryParam(qp), 'refreshModel')) { - this.refresh(); - } - } - - return true; - }, - - finalizeQueryParamChange: function(params, finalParams, transition) { - if (this.routeName !== 'application') { return true; } - - // Transition object is absent for intermediate transitions. - if (!transition) { return; } - - var handlerInfos = transition.state.handlerInfos; - var router = this.router; - var qpMeta = router._queryParamsFor(handlerInfos[handlerInfos.length-1].name); - var changes = router._qpUpdates; - var replaceUrl; - - stashParamNames(router, handlerInfos); - - for (var i = 0, len = qpMeta.qps.length; i < len; ++i) { - var qp = qpMeta.qps[i]; - var route = qp.route; - var controller = route.controller; - var presentKey = qp.urlKey in params && qp.urlKey; - - // Do a reverse lookup to see if the changed query - // param URL key corresponds to a QP property on - // this controller. - var value, svalue; - if (changes && qp.urlKey in changes) { - // Value updated in/before setupController - value = get(controller, qp.prop); - svalue = route.serializeQueryParam(value, qp.urlKey, qp.type); - } else { - if (presentKey) { - svalue = params[presentKey]; - value = route.deserializeQueryParam(svalue, qp.urlKey, qp.type); - } else { - // No QP provided; use default value. - svalue = qp.sdef; - value = copyDefaultValue(qp.def); - } - } - - controller._qpDelegate = get(this, '_qp.states.inactive'); - - var thisQueryParamChanged = (svalue !== qp.svalue); - if (thisQueryParamChanged) { - if (transition.queryParamsOnly && replaceUrl !== false) { - var options = route._optionsForQueryParam(qp); - var replaceConfigValue = get(options, 'replace'); - if (replaceConfigValue) { - replaceUrl = true; - } else if (replaceConfigValue === false) { - // Explicit pushState wins over any other replaceStates. - replaceUrl = false; - } - } - - set(controller, qp.prop, value); - } - - // Stash current serialized value of controller. - qp.svalue = svalue; - - var thisQueryParamHasDefaultValue = (qp.sdef === svalue); - if (!thisQueryParamHasDefaultValue) { - finalParams.push({ - value: svalue, - visible: true, - key: presentKey || qp.urlKey - }); - } - } - - if (replaceUrl) { - transition.method('replace'); - } - - forEach(qpMeta.qps, function(qp) { - var routeQpMeta = get(qp.route, '_qp'); - var finalizedController = qp.route.controller; - finalizedController._qpDelegate = get(routeQpMeta, 'states.active'); - }); - - router._qpUpdates = null; - } - }, - - /** - @deprecated - - Please use `actions` instead. - @method events - */ - events: null, - - /** - This hook is executed when the router completely exits this route. It is - not executed when the model for the route changes. - - @method deactivate - */ - deactivate: K, - - /** - This hook is executed when the router enters the route. It is not executed - when the model for the route changes. - - @method activate - */ - activate: K, - - /** - Transition the application into another route. The route may - be either a single route or route path: - - ```javascript - this.transitionTo('blogPosts'); - this.transitionTo('blogPosts.recentEntries'); - ``` - - Optionally supply a model for the route in question. The model - will be serialized into the URL using the `serialize` hook of - the route: - - ```javascript - this.transitionTo('blogPost', aPost); - ``` - - If a literal is passed (such as a number or a string), it will - be treated as an identifier instead. In this case, the `model` - hook of the route will be triggered: - - ```javascript - this.transitionTo('blogPost', 1); - ``` - - Multiple models will be applied last to first recursively up the - resource tree. - - ```javascript - App.Router.map(function() { - this.resource('blogPost', { path:':blogPostId' }, function() { - this.resource('blogComment', { path: ':blogCommentId' }); - }); - }); - - this.transitionTo('blogComment', aPost, aComment); - this.transitionTo('blogComment', 1, 13); - ``` - - It is also possible to pass a URL (a string that starts with a - `/`). This is intended for testing and debugging purposes and - should rarely be used in production code. - - ```javascript - this.transitionTo('/'); - this.transitionTo('/blog/post/1/comment/13'); - this.transitionTo('/blog/posts?sort=title'); - ``` - - An options hash with a `queryParams` property may be provided as - the final argument to add query parameters to the destination URL. - - ```javascript - this.transitionTo('blogPost', 1, { - queryParams: {showComments: 'true'} - }); - - // if you just want to transition the query parameters without changing the route - this.transitionTo({queryParams: {sort: 'date'}}); - ``` - - See also 'replaceWith'. - - Simple Transition Example - - ```javascript - App.Router.map(function() { - this.route('index'); - this.route('secret'); - this.route('fourOhFour', { path: '*:' }); - }); - - App.IndexRoute = Ember.Route.extend({ - actions: { - moveToSecret: function(context) { - if (authorized()) { - this.transitionTo('secret', context); - } else { - this.transitionTo('fourOhFour'); - } - } - } - }); - ``` - - Transition to a nested route - - ```javascript - App.Router.map(function() { - this.resource('articles', { path: '/articles' }, function() { - this.route('new'); - }); - }); - - App.IndexRoute = Ember.Route.extend({ - actions: { - transitionToNewArticle: function() { - this.transitionTo('articles.new'); - } - } - }); - ``` - - Multiple Models Example - - ```javascript - App.Router.map(function() { - this.route('index'); - - this.resource('breakfast', { path: ':breakfastId' }, function() { - this.resource('cereal', { path: ':cerealId' }); - }); - }); - - App.IndexRoute = Ember.Route.extend({ - actions: { - moveToChocolateCereal: function() { - var cereal = { cerealId: 'ChocolateYumminess' }; - var breakfast = { breakfastId: 'CerealAndMilk' }; - - this.transitionTo('cereal', breakfast, cereal); - } - } - }); - ``` - - Nested Route with Query String Example - - ```javascript - App.Router.map(function() { - this.resource('fruits', function() { - this.route('apples'); - }); - }); - - App.IndexRoute = Ember.Route.extend({ - actions: { - transitionToApples: function() { - this.transitionTo('fruits.apples', {queryParams: {color: 'red'}}); - } - } - }); - ``` - - @method transitionTo - @param {String} name the name of the route or a URL - @param {...Object} models the model(s) or identifier(s) to be used while - transitioning to the route. - @param {Object} [options] optional hash with a queryParams property - containing a mapping of query parameters - @return {Transition} the transition object associated with this - attempted transition - */ - transitionTo: function(name, context) { - var router = this.router; - return router.transitionTo.apply(router, arguments); - }, - - /** - Perform a synchronous transition into another route without attempting - to resolve promises, update the URL, or abort any currently active - asynchronous transitions (i.e. regular transitions caused by - `transitionTo` or URL changes). - - This method is handy for performing intermediate transitions on the - way to a final destination route, and is called internally by the - default implementations of the `error` and `loading` handlers. - - @method intermediateTransitionTo - @param {String} name the name of the route - @param {...Object} models the model(s) to be used while transitioning - to the route. - @since 1.2.0 - */ - intermediateTransitionTo: function() { - var router = this.router; - router.intermediateTransitionTo.apply(router, arguments); - }, - - /** - Refresh the model on this route and any child routes, firing the - `beforeModel`, `model`, and `afterModel` hooks in a similar fashion - to how routes are entered when transitioning in from other route. - The current route params (e.g. `article_id`) will be passed in - to the respective model hooks, and if a different model is returned, - `setupController` and associated route hooks will re-fire as well. - - An example usage of this method is re-querying the server for the - latest information using the same parameters as when the route - was first entered. - - Note that this will cause `model` hooks to fire even on routes - that were provided a model object when the route was initially - entered. - - @method refresh - @return {Transition} the transition object associated with this - attempted transition - @since 1.4.0 - */ - refresh: function() { - return this.router.router.refresh(this); - }, - - /** - Transition into another route while replacing the current URL, if possible. - This will replace the current history entry instead of adding a new one. - Beside that, it is identical to `transitionTo` in all other respects. See - 'transitionTo' for additional information regarding multiple models. - - Example - - ```javascript - App.Router.map(function() { - this.route('index'); - this.route('secret'); - }); - - App.SecretRoute = Ember.Route.extend({ - afterModel: function() { - if (!authorized()){ - this.replaceWith('index'); - } - } - }); - ``` - - @method replaceWith - @param {String} name the name of the route or a URL - @param {...Object} models the model(s) or identifier(s) to be used while - transitioning to the route. - @return {Transition} the transition object associated with this - attempted transition - */ - replaceWith: function() { - var router = this.router; - return router.replaceWith.apply(router, arguments); - }, - - /** - Sends an action to the router, which will delegate it to the currently - active route hierarchy per the bubbling rules explained under `actions`. - - Example - - ```javascript - App.Router.map(function() { - this.route('index'); - }); - - App.ApplicationRoute = Ember.Route.extend({ - actions: { - track: function(arg) { - console.log(arg, 'was clicked'); - } - } - }); - - App.IndexRoute = Ember.Route.extend({ - actions: { - trackIfDebug: function(arg) { - if (debug) { - this.send('track', arg); - } - } - } - }); - ``` - - @method send - @param {String} name the name of the action to trigger - @param {...*} args - */ - send: function() { - if (this.router || !Ember.testing) { - this.router.send.apply(this.router, arguments); - } else { - var name = arguments[0]; - var args = slice.call(arguments, 1); - var action = this._actions[name]; - if (action) { - return this._actions[name].apply(this, args); - } - } - }, - - /** - This hook is the entry point for router.js - - @private - @method setup - */ - setup: function(context, transition) { - var controllerName = this.controllerName || this.routeName; - var controller = this.controllerFor(controllerName, true); - - if (!controller) { - controller = this.generateController(controllerName, context); - } - - // Assign the route's controller so that it can more easily be - // referenced in action handlers - this.controller = controller; - - if (this.setupControllers) { - Ember.deprecate("Ember.Route.setupControllers is deprecated. Please use Ember.Route.setupController(controller, model) instead."); - this.setupControllers(controller, context); - } else { - var states = get(this, '_qp.states'); - if (transition) { - // Update the model dep values used to calculate cache keys. - stashParamNames(this.router, transition.state.handlerInfos); - controller._qpDelegate = states.changingKeys; - controller._updateCacheParams(transition.params); - } - controller._qpDelegate = states.allowOverrides; - - if (transition) { - var qpValues = getQueryParamsFor(this, transition.state); - controller.setProperties(qpValues); - } - - this.setupController(controller, context, transition); - } - - if (this.renderTemplates) { - Ember.deprecate("Ember.Route.renderTemplates is deprecated. Please use Ember.Route.renderTemplate(controller, model) instead."); - this.renderTemplates(context); - } else { - this.renderTemplate(controller, context); - } - }, - - /** - This hook is the first of the route entry validation hooks - called when an attempt is made to transition into a route - or one of its children. It is called before `model` and - `afterModel`, and is appropriate for cases when: - - 1) A decision can be made to redirect elsewhere without - needing to resolve the model first. - 2) Any async operations need to occur first before the - model is attempted to be resolved. - - This hook is provided the current `transition` attempt - as a parameter, which can be used to `.abort()` the transition, - save it for a later `.retry()`, or retrieve values set - on it from a previous hook. You can also just call - `this.transitionTo` to another route to implicitly - abort the `transition`. - - You can return a promise from this hook to pause the - transition until the promise resolves (or rejects). This could - be useful, for instance, for retrieving async code from - the server that is required to enter a route. - - ```javascript - App.PostRoute = Ember.Route.extend({ - beforeModel: function(transition) { - if (!App.Post) { - return Ember.$.getScript('/models/post.js'); - } - } - }); - ``` - - If `App.Post` doesn't exist in the above example, - `beforeModel` will use jQuery's `getScript`, which - returns a promise that resolves after the server has - successfully retrieved and executed the code from the - server. Note that if an error were to occur, it would - be passed to the `error` hook on `Ember.Route`, but - it's also possible to handle errors specific to - `beforeModel` right from within the hook (to distinguish - from the shared error handling behavior of the `error` - hook): - - ```javascript - App.PostRoute = Ember.Route.extend({ - beforeModel: function(transition) { - if (!App.Post) { - var self = this; - return Ember.$.getScript('post.js').then(null, function(e) { - self.transitionTo('help'); - - // Note that the above transitionTo will implicitly - // halt the transition. If you were to return - // nothing from this promise reject handler, - // according to promise semantics, that would - // convert the reject into a resolve and the - // transition would continue. To propagate the - // error so that it'd be handled by the `error` - // hook, you would have to - return Ember.RSVP.reject(e); - }); - } - } - }); - ``` - - @method beforeModel - @param {Transition} transition - @return {Promise} if the value returned from this hook is - a promise, the transition will pause until the transition - resolves. Otherwise, non-promise return values are not - utilized in any way. - */ - beforeModel: K, - - /** - This hook is called after this route's model has resolved. - It follows identical async/promise semantics to `beforeModel` - but is provided the route's resolved model in addition to - the `transition`, and is therefore suited to performing - logic that can only take place after the model has already - resolved. - - ```javascript - App.PostsRoute = Ember.Route.extend({ - afterModel: function(posts, transition) { - if (posts.get('length') === 1) { - this.transitionTo('post.show', posts.get('firstObject')); - } - } - }); - ``` - - Refer to documentation for `beforeModel` for a description - of transition-pausing semantics when a promise is returned - from this hook. - - @method afterModel - @param {Object} resolvedModel the value returned from `model`, - or its resolved value if it was a promise - @param {Transition} transition - @return {Promise} if the value returned from this hook is - a promise, the transition will pause until the transition - resolves. Otherwise, non-promise return values are not - utilized in any way. - */ - afterModel: K, - - /** - A hook you can implement to optionally redirect to another route. - - If you call `this.transitionTo` from inside of this hook, this route - will not be entered in favor of the other hook. - - `redirect` and `afterModel` behave very similarly and are - called almost at the same time, but they have an important - distinction in the case that, from one of these hooks, a - redirect into a child route of this route occurs: redirects - from `afterModel` essentially invalidate the current attempt - to enter this route, and will result in this route's `beforeModel`, - `model`, and `afterModel` hooks being fired again within - the new, redirecting transition. Redirects that occur within - the `redirect` hook, on the other hand, will _not_ cause - these hooks to be fired again the second time around; in - other words, by the time the `redirect` hook has been called, - both the resolved model and attempted entry into this route - are considered to be fully validated. - - @method redirect - @param {Object} model the model for this route - @param {Transition} transition the transition object associated with the current transition - */ - redirect: K, - - /** - Called when the context is changed by router.js. - - @private - @method contextDidChange - */ - contextDidChange: function() { - this.currentModel = this.context; - }, - - /** - A hook you can implement to convert the URL into the model for - this route. - - ```javascript - App.Router.map(function() { - this.resource('post', { path: '/posts/:post_id' }); - }); - ``` - - The model for the `post` route is `store.find('post', params.post_id)`. - - By default, if your route has a dynamic segment ending in `_id`: - - * The model class is determined from the segment (`post_id`'s - class is `App.Post`) - * The find method is called on the model class with the value of - the dynamic segment. - - Note that for routes with dynamic segments, this hook is not always - executed. If the route is entered through a transition (e.g. when - using the `link-to` Handlebars helper or the `transitionTo` method - of routes), and a model context is already provided this hook - is not called. - - A model context does not include a primitive string or number, - which does cause the model hook to be called. - - Routes without dynamic segments will always execute the model hook. - - ```javascript - // no dynamic segment, model hook always called - this.transitionTo('posts'); - - // model passed in, so model hook not called - thePost = store.find('post', 1); - this.transitionTo('post', thePost); - - // integer passed in, model hook is called - this.transitionTo('post', 1); - ``` - - - This hook follows the asynchronous/promise semantics - described in the documentation for `beforeModel`. In particular, - if a promise returned from `model` fails, the error will be - handled by the `error` hook on `Ember.Route`. - - Example - - ```javascript - App.PostRoute = Ember.Route.extend({ - model: function(params) { - return this.store.find('post', params.post_id); - } - }); - ``` - - @method model - @param {Object} params the parameters extracted from the URL - @param {Transition} transition - @return {Object|Promise} the model for this route. If - a promise is returned, the transition will pause until - the promise resolves, and the resolved value of the promise - will be used as the model for this route. - */ - model: function(params, transition) { - var match, name, sawParams, value; - - var queryParams = get(this, '_qp.map'); - - for (var prop in params) { - if (prop === 'queryParams' || (queryParams && prop in queryParams)) { - continue; - } - - if (match = prop.match(/^(.*)_id$/)) { - name = match[1]; - value = params[prop]; - } - sawParams = true; - } - - if (!name && sawParams) { return copy(params); } - else if (!name) { - if (transition.resolveIndex < 1) { return; } - - var parentModel = transition.state.handlerInfos[transition.resolveIndex-1].context; - - return parentModel; - } - - return this.findModel(name, value); - }, - - /** - @private - @method deserialize - @param {Object} params the parameters extracted from the URL - @param {Transition} transition - @return {Object|Promise} the model for this route. - - Router.js hook. - */ - deserialize: function(params, transition) { - return this.model(this.paramsFor(this.routeName), transition); - }, - - /** - - @method findModel - @param {String} type the model type - @param {Object} value the value passed to find - */ - findModel: function(){ - var store = get(this, 'store'); - return store.find.apply(store, arguments); - }, - - /** - Store property provides a hook for data persistence libraries to inject themselves. - - By default, this store property provides the exact same functionality previously - in the model hook. - - Currently, the required interface is: - - `store.find(modelName, findArguments)` - - @method store - @param {Object} store - */ - store: computed(function(){ - var container = this.container; - var routeName = this.routeName; - var namespace = get(this, 'router.namespace'); - - return { - find: function(name, value) { - var modelClass = container.lookupFactory('model:' + name); - - Ember.assert("You used the dynamic segment " + name + "_id in your route " + - routeName + ", but " + namespace + "." + classify(name) + - " did not exist and you did not override your route's `model` " + - "hook.", !!modelClass); - - if (!modelClass) { return; } - - Ember.assert(classify(name) + ' has no method `find`.', typeof modelClass.find === 'function'); - - return modelClass.find(value); - } - }; - }), - - /** - A hook you can implement to convert the route's model into parameters - for the URL. - - ```javascript - App.Router.map(function() { - this.resource('post', { path: '/posts/:post_id' }); - }); - - App.PostRoute = Ember.Route.extend({ - model: function(params) { - // the server returns `{ id: 12 }` - return Ember.$.getJSON('/posts/' + params.post_id); - }, - - serialize: function(model) { - // this will make the URL `/posts/12` - return { post_id: model.id }; - } - }); - ``` - - The default `serialize` method will insert the model's `id` into the - route's dynamic segment (in this case, `:post_id`) if the segment contains '_id'. - If the route has multiple dynamic segments or does not contain '_id', `serialize` - will return `Ember.getProperties(model, params)` - - This method is called when `transitionTo` is called with a context - in order to populate the URL. - - @method serialize - @param {Object} model the route's model - @param {Array} params an Array of parameter names for the current - route (in the example, `['post_id']`. - @return {Object} the serialized parameters - */ - serialize: function(model, params) { - if (params.length < 1) { return; } - if (!model) { return; } - - var name = params[0], object = {}; - - if (params.length === 1) { - if (name in model) { - object[name] = get(model, name); - } else if (/_id$/.test(name)) { - object[name] = get(model, "id"); - } - } else { - object = getProperties(model, params); - } - - return object; - }, - - /** - A hook you can use to setup the controller for the current route. - - This method is called with the controller for the current route and the - model supplied by the `model` hook. - - By default, the `setupController` hook sets the `model` property of - the controller to the `model`. - - If you implement the `setupController` hook in your Route, it will - prevent this default behavior. If you want to preserve that behavior - when implementing your `setupController` function, make sure to call - `_super`: - - ```javascript - App.PhotosRoute = Ember.Route.extend({ - model: function() { - return this.store.find('photo'); - }, - - setupController: function (controller, model) { - // Call _super for default behavior - this._super(controller, model); - // Implement your custom setup after - this.controllerFor('application').set('showingPhotos', true); - } - }); - ``` - - This means that your template will get a proxy for the model as its - context, and you can act as though the model itself was the context. - - The provided controller will be one resolved based on the name - of this route. - - If no explicit controller is defined, Ember will automatically create - an appropriate controller for the model. - - * if the model is an `Ember.Array` (including record arrays from Ember - Data), the controller is an `Ember.ArrayController`. - * otherwise, the controller is an `Ember.ObjectController`. - - As an example, consider the router: - - ```javascript - App.Router.map(function() { - this.resource('post', { path: '/posts/:post_id' }); - }); - ``` - - For the `post` route, a controller named `App.PostController` would - be used if it is defined. If it is not defined, an `Ember.ObjectController` - instance would be used. - - Example - - ```javascript - App.PostRoute = Ember.Route.extend({ - setupController: function(controller, model) { - controller.set('model', model); - } - }); - ``` - - @method setupController - @param {Controller} controller instance - @param {Object} model - */ - setupController: function(controller, context, transition) { - if (controller && (context !== undefined)) { - set(controller, 'model', context); - } - }, - - /** - Returns the controller for a particular route or name. - - The controller instance must already have been created, either through entering the - associated route or using `generateController`. - - ```javascript - App.PostRoute = Ember.Route.extend({ - setupController: function(controller, post) { - this._super(controller, post); - this.controllerFor('posts').set('currentPost', post); - } - }); - ``` - - @method controllerFor - @param {String} name the name of the route or controller - @return {Ember.Controller} - */ - controllerFor: function(name, _skipAssert) { - var container = this.container; - var route = container.lookup('route:'+name); - var controller; - - if (route && route.controllerName) { - name = route.controllerName; - } - - controller = container.lookup('controller:' + name); - - // NOTE: We're specifically checking that skipAssert is true, because according - // to the old API the second parameter was model. We do not want people who - // passed a model to skip the assertion. - Ember.assert("The controller named '"+name+"' could not be found. Make sure " + - "that this route exists and has already been entered at least " + - "once. If you are accessing a controller not associated with a " + - "route, make sure the controller class is explicitly defined.", - controller || _skipAssert === true); - - return controller; - }, - - /** - Generates a controller for a route. - - If the optional model is passed then the controller type is determined automatically, - e.g., an ArrayController for arrays. - - Example - - ```javascript - App.PostRoute = Ember.Route.extend({ - setupController: function(controller, post) { - this._super(controller, post); - this.generateController('posts', post); - } - }); - ``` - - @method generateController - @param {String} name the name of the controller - @param {Object} model the model to infer the type of the controller (optional) - */ - generateController: function(name, model) { - var container = this.container; - - model = model || this.modelFor(name); - - return generateController(container, name, model); - }, - - /** - Returns the model of a parent (or any ancestor) route - in a route hierarchy. During a transition, all routes - must resolve a model object, and if a route - needs access to a parent route's model in order to - resolve a model (or just reuse the model from a parent), - it can call `this.modelFor(theNameOfParentRoute)` to - retrieve it. - - Example - - ```javascript - App.Router.map(function() { - this.resource('post', { path: '/post/:post_id' }, function() { - this.resource('comments'); - }); - }); - - App.CommentsRoute = Ember.Route.extend({ - afterModel: function() { - this.set('post', this.modelFor('post')); - } - }); - ``` - - @method modelFor - @param {String} name the name of the route - @return {Object} the model object - */ - modelFor: function(name) { - var route = this.container.lookup('route:' + name); - var transition = this.router ? this.router.router.activeTransition : null; - - // If we are mid-transition, we want to try and look up - // resolved parent contexts on the current transitionEvent. - if (transition) { - var modelLookupName = (route && route.routeName) || name; - if (transition.resolvedModels.hasOwnProperty(modelLookupName)) { - return transition.resolvedModels[modelLookupName]; - } - } - - return route && route.currentModel; - }, - - /** - A hook you can use to render the template for the current route. - - This method is called with the controller for the current route and the - model supplied by the `model` hook. By default, it renders the route's - template, configured with the controller for the route. - - This method can be overridden to set up and render additional or - alternative templates. - - ```javascript - App.PostsRoute = Ember.Route.extend({ - renderTemplate: function(controller, model) { - var favController = this.controllerFor('favoritePost'); - - // Render the `favoritePost` template into - // the outlet `posts`, and display the `favoritePost` - // controller. - this.render('favoritePost', { - outlet: 'posts', - controller: favController - }); - } - }); - ``` - - @method renderTemplate - @param {Object} controller the route's controller - @param {Object} model the route's model - */ - renderTemplate: function(controller, model) { - this.render(); - }, - - /** - `render` is used to render a template into a region of another template - (indicated by an `{{outlet}}`). `render` is used both during the entry - phase of routing (via the `renderTemplate` hook) and later in response to - user interaction. - - For example, given the following minimal router and templates: - - ```javascript - Router.map(function() { - this.resource('photos'); - }); - ``` - - ```handlebars - -
    - {{outlet "anOutletName"}} -
    - ``` - - ```handlebars - -

    Photos

    - ``` - - You can render `photos.hbs` into the `"anOutletName"` outlet of - `application.hbs` by calling `render`: - - ```javascript - // posts route - Ember.Route.extend({ - renderTemplate: function(){ - this.render('photos', { - into: 'application', - outlet: 'anOutletName' - }) - } - }); - ``` - - `render` additionally allows you to supply which `view`, `controller`, and - `model` objects should be loaded and associated with the rendered template. - - - ```javascript - // posts route - Ember.Route.extend({ - renderTemplate: function(controller, model){ - this.render('posts', { // the template to render, referenced by name - into: 'application', // the template to render into, referenced by name - outlet: 'anOutletName', // the outlet inside `options.template` to render into. - view: 'aViewName', // the view to use for this template, referenced by name - controller: 'someControllerName', // the controller to use for this template, referenced by name - model: model // the model to set on `options.controller`. - }) - } - }); - ``` - - The string values provided for the template name, view, and controller - will eventually pass through to the resolver for lookup. See - Ember.Resolver for how these are mapped to JavaScript objects in your - application. - - Not all options need to be passed to `render`. Default values will be used - based on the name of the route specified in the router or the Route's - `controllerName`, `viewName` and `templateName` properties. - - For example: - - ```javascript - // router - Router.map(function() { - this.route('index'); - this.resource('post', { path: '/posts/:post_id' }); - }); - ``` - - ```javascript - // post route - PostRoute = App.Route.extend({ - renderTemplate: function() { - this.render(); // all defaults apply - } - }); - ``` - - The name of the `PostRoute`, defined by the router, is `post`. - - The following equivalent default options will be applied when - the Route calls `render`: - - ```javascript - // - this.render('post', { // the template name associated with 'post' Route - into: 'application', // the parent route to 'post' Route - outlet: 'main', // {{outlet}} and {{outlet 'main' are synonymous}}, - view: 'post', // the view associated with the 'post' Route - controller: 'post', // the controller associated with the 'post' Route - }) - ``` - - By default the controller's `model` will be the route's model, so it does not - need to be passed unless you wish to change which model is being used. - - @method render - @param {String} name the name of the template to render - @param {Object} [options] the options - @param {String} [options.into] the template to render into, - referenced by name. Defaults to the parent template - @param {String} [options.outlet] the outlet inside `options.template` to render into. - Defaults to 'main' - @param {String} [options.controller] the controller to use for this template, - referenced by name. Defaults to the Route's paired controller - @param {String} [options.model] the model object to set on `options.controller` - Defaults to the return value of the Route's model hook - */ - render: function(_name, options) { - Ember.assert("The name in the given arguments is undefined", arguments.length > 0 ? !isNone(arguments[0]) : true); - - var namePassed = typeof _name === 'string' && !!_name; - var name; - - if (typeof _name === 'object' && !options) { - name = this.routeName; - options = _name; - } else { - name = _name; - } - - var templateName; - - if (name) { - name = name.replace(/\//g, '.'); - templateName = name; - } else { - name = this.routeName; - templateName = this.templateName || name; - } - - var renderOptions = buildRenderOptions(this, namePassed, name, options); - - var LOG_VIEW_LOOKUPS = get(this.router, 'namespace.LOG_VIEW_LOOKUPS'); - var viewName = options && options.view || namePassed && name || this.viewName || name; - var view, template; - - var ViewClass = this.container.lookupFactory('view:' + viewName); - if (ViewClass) { - view = setupView(ViewClass, renderOptions); - if (!get(view, 'template')) { - view.set('template', this.container.lookup('template:' + templateName)); - } - if (LOG_VIEW_LOOKUPS) { - Ember.Logger.info("Rendering " + renderOptions.name + " with " + view, { fullName: 'view:' + renderOptions.name }); - } - } else { - template = this.container.lookup('template:' + templateName); - if (!template) { - Ember.assert("Could not find \"" + name + "\" template or view.", arguments.length === 0 || Ember.isEmpty(arguments[0])); - if (LOG_VIEW_LOOKUPS) { - Ember.Logger.info("Could not find \"" + name + "\" template or view. Nothing will be rendered", { fullName: 'template:' + name }); - } - return; - } - var defaultView = renderOptions.into ? 'view:default' : 'view:toplevel'; - ViewClass = this.container.lookupFactory(defaultView); - view = setupView(ViewClass, renderOptions); - if (!get(view, 'template')) { - view.set('template', template); - } - if (LOG_VIEW_LOOKUPS) { - Ember.Logger.info("Rendering " + renderOptions.name + " with default view " + view, { fullName: 'view:' + renderOptions.name }); - } - } - - if (renderOptions.outlet === 'main') { this.lastRenderedTemplate = name; } - appendView(this, view, renderOptions); - }, - - /** - Disconnects a view that has been rendered into an outlet. - - You may pass any or all of the following options to `disconnectOutlet`: - - * `outlet`: the name of the outlet to clear (default: 'main') - * `parentView`: the name of the view containing the outlet to clear - (default: the view rendered by the parent route) - - Example: - - ```javascript - App.ApplicationRoute = App.Route.extend({ - actions: { - showModal: function(evt) { - this.render(evt.modalName, { - outlet: 'modal', - into: 'application' - }); - }, - hideModal: function(evt) { - this.disconnectOutlet({ - outlet: 'modal', - parentView: 'application' - }); - } - } - }); - ``` - - Alternatively, you can pass the `outlet` name directly as a string. - - Example: - - ```javascript - hideModal: function(evt) { - this.disconnectOutlet('modal'); - } - ``` - - @method disconnectOutlet - @param {Object|String} options the options hash or outlet name - */ - disconnectOutlet: function(options) { - if (!options || typeof options === "string") { - var outletName = options; - options = {}; - options.outlet = outletName; - } - options.parentView = options.parentView ? options.parentView.replace(/\//g, '.') : parentTemplate(this); - options.outlet = options.outlet || 'main'; - - var parentView = this.router._lookupActiveView(options.parentView); - if (parentView) { parentView.disconnectOutlet(options.outlet); } - }, - - willDestroy: function() { - this.teardownViews(); - }, - - /** - @private - - @method teardownViews - */ - teardownViews: function() { - // Tear down the top level view - if (this.teardownTopLevelView) { this.teardownTopLevelView(); } - - // Tear down any outlets rendered with 'into' - var teardownOutletViews = this.teardownOutletViews || []; - forEach(teardownOutletViews, function(teardownOutletView) { - teardownOutletView(); - }); - - delete this.teardownTopLevelView; - delete this.teardownOutletViews; - delete this.lastRenderedTemplate; - } - }); - - - // TODO add mixin directly to `Route` class definition above, once this - // feature is merged: - Route.reopen(Evented); - - - var defaultQPMeta = { - qps: [], - map: {}, - states: {} - }; - - function parentRoute(route) { - var handlerInfo = handlerInfoFor(route, route.router.router.state.handlerInfos, -1); - return handlerInfo && handlerInfo.handler; - } - - function handlerInfoFor(route, handlerInfos, _offset) { - if (!handlerInfos) { return; } - - var offset = _offset || 0; - var current; - for (var i=0, l=handlerInfos.length; i " + routeName, { fullName: routeName }); - } - } - - handler.routeName = name; - return handler; - }; - }, - - _setupRouter: function(router, location) { - var lastURL, emberRouter = this; - - router.getHandler = this._getHandlerFunction(); - - var doUpdateURL = function() { - location.setURL(lastURL); - }; - - router.updateURL = function(path) { - lastURL = path; - run.once(doUpdateURL); - }; - - if (location.replaceURL) { - var doReplaceURL = function() { - location.replaceURL(lastURL); - }; - - router.replaceURL = function(path) { - lastURL = path; - run.once(doReplaceURL); - }; - } - - router.didTransition = function(infos) { - emberRouter.didTransition(infos); - }; - }, - - _serializeQueryParams: function(targetRouteName, queryParams) { - var groupedByUrlKey = {}; - - forEachQueryParam(this, targetRouteName, queryParams, function(key, value, qp) { - var urlKey = qp.urlKey; - if (!groupedByUrlKey[urlKey]) { - groupedByUrlKey[urlKey] = []; - } - groupedByUrlKey[urlKey].push({ - qp: qp, - value: value - }); - delete queryParams[key]; - }); - - for (var key in groupedByUrlKey) { - var qps = groupedByUrlKey[key]; - Ember.assert(fmt("You're not allowed to have more than one controller " + - "property map to the same query param key, but both " + - "`%@` and `%@` map to `%@`. You can fix this by mapping " + - "one of the controller properties to a different query " + - "param key via the `as` config option, e.g. `%@: { as: 'other-%@' }`", - [qps[0].qp.fprop, qps[1] ? qps[1].qp.fprop : "", qps[0].qp.urlKey, qps[0].qp.prop, qps[0].qp.prop]), qps.length <= 1); - var qp = qps[0].qp; - queryParams[qp.urlKey] = qp.route.serializeQueryParam(qps[0].value, qp.urlKey, qp.type); - } - }, - - _deserializeQueryParams: function(targetRouteName, queryParams) { - forEachQueryParam(this, targetRouteName, queryParams, function(key, value, qp) { - delete queryParams[key]; - queryParams[qp.prop] = qp.route.deserializeQueryParam(value, qp.urlKey, qp.type); - }); - }, - - _pruneDefaultQueryParamValues: function(targetRouteName, queryParams) { - var qps = this._queryParamsFor(targetRouteName); - for (var key in queryParams) { - var qp = qps.map[key]; - if (qp && qp.sdef === queryParams[key]) { - delete queryParams[key]; - } - } - }, - - _doTransition: function(_targetRouteName, models, _queryParams) { - var targetRouteName = _targetRouteName || getActiveTargetName(this.router); - Ember.assert("The route " + targetRouteName + " was not found", targetRouteName && this.router.hasRoute(targetRouteName)); - - var queryParams = {}; - merge(queryParams, _queryParams); - this._prepareQueryParams(targetRouteName, models, queryParams); - - var transitionArgs = routeArgs(targetRouteName, models, queryParams); - var transitionPromise = this.router.transitionTo.apply(this.router, transitionArgs); - - listenForTransitionErrors(transitionPromise); - - return transitionPromise; - }, - - _prepareQueryParams: function(targetRouteName, models, queryParams) { - this._hydrateUnsuppliedQueryParams(targetRouteName, models, queryParams); - this._serializeQueryParams(targetRouteName, queryParams); - this._pruneDefaultQueryParamValues(targetRouteName, queryParams); - }, - - /** - Returns a merged query params meta object for a given route. - Useful for asking a route what its known query params are. - */ - _queryParamsFor: function(leafRouteName) { - if (this._qpCache[leafRouteName]) { - return this._qpCache[leafRouteName]; - } - - var map = {}, qps = []; - this._qpCache[leafRouteName] = { - map: map, - qps: qps - }; - - var routerjs = this.router; - var recogHandlerInfos = routerjs.recognizer.handlersFor(leafRouteName); - - for (var i = 0, len = recogHandlerInfos.length; i < len; ++i) { - var recogHandler = recogHandlerInfos[i]; - var route = routerjs.getHandler(recogHandler.handler); - var qpMeta = get(route, '_qp'); - - if (!qpMeta) { continue; } - - merge(map, qpMeta.map); - qps.push.apply(qps, qpMeta.qps); - } - - return { - qps: qps, - map: map - }; - }, - - /* - becomeResolved: function(payload, resolvedContext) { - var params = this.serialize(resolvedContext); - - if (payload) { - this.stashResolvedModel(payload, resolvedContext); - payload.params = payload.params || {}; - payload.params[this.name] = params; - } - - return this.factory('resolved', { - context: resolvedContext, - name: this.name, - handler: this.handler, - params: params - }); - }, - */ - - _hydrateUnsuppliedQueryParams: function(leafRouteName, contexts, queryParams) { - var state = calculatePostTransitionState(this, leafRouteName, contexts); - var handlerInfos = state.handlerInfos; - var appCache = this._bucketCache; - - stashParamNames(this, handlerInfos); - - for (var i = 0, len = handlerInfos.length; i < len; ++i) { - var route = handlerInfos[i].handler; - var qpMeta = get(route, '_qp'); - - for (var j = 0, qpLen = qpMeta.qps.length; j < qpLen; ++j) { - var qp = qpMeta.qps[j]; - var presentProp = qp.prop in queryParams && qp.prop || - qp.fprop in queryParams && qp.fprop; - - if (presentProp) { - if (presentProp !== qp.fprop) { - queryParams[qp.fprop] = queryParams[presentProp]; - delete queryParams[presentProp]; - } - } else { - var controllerProto = qp.cProto; - var cacheMeta = get(controllerProto, '_cacheMeta'); - - var cacheKey = controllerProto._calculateCacheKey(qp.ctrl, cacheMeta[qp.prop].parts, state.params); - queryParams[qp.fprop] = appCache.lookup(cacheKey, qp.prop, qp.def); - } - } - } - }, - - _scheduleLoadingEvent: function(transition, originRoute) { - this._cancelLoadingEvent(); - this._loadingStateTimer = run.scheduleOnce('routerTransitions', this, '_fireLoadingEvent', transition, originRoute); - }, - - _fireLoadingEvent: function(transition, originRoute) { - if (!this.router.activeTransition) { - // Don't fire an event if we've since moved on from - // the transition that put us in a loading state. - return; - } - - transition.trigger(true, 'loading', transition, originRoute); - }, - - _cancelLoadingEvent: function () { - if (this._loadingStateTimer) { - run.cancel(this._loadingStateTimer); - } - this._loadingStateTimer = null; - } - }); - - /* - Helper function for iterating root-ward, starting - from (but not including) the provided `originRoute`. - - Returns true if the last callback fired requested - to bubble upward. - - @private - */ - function forEachRouteAbove(originRoute, transition, callback) { - var handlerInfos = transition.state.handlerInfos; - var originRouteFound = false; - var handlerInfo, route; - - for (var i = handlerInfos.length - 1; i >= 0; --i) { - handlerInfo = handlerInfos[i]; - route = handlerInfo.handler; - - if (!originRouteFound) { - if (originRoute === route) { - originRouteFound = true; - } - continue; - } - - if (callback(route, handlerInfos[i + 1].handler) !== true) { - return false; - } - } - return true; - } - - // These get invoked when an action bubbles above ApplicationRoute - // and are not meant to be overridable. - var defaultActionHandlers = { - - willResolveModel: function(transition, originRoute) { - originRoute.router._scheduleLoadingEvent(transition, originRoute); - }, - - error: function(error, transition, originRoute) { - // Attempt to find an appropriate error substate to enter. - var router = originRoute.router; - - var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { - var childErrorRouteName = findChildRouteName(route, childRoute, 'error'); - if (childErrorRouteName) { - router.intermediateTransitionTo(childErrorRouteName, error); - return; - } - return true; - }); - - if (tryTopLevel) { - // Check for top-level error state to enter. - if (routeHasBeenDefined(originRoute.router, 'application_error')) { - router.intermediateTransitionTo('application_error', error); - return; - } - } - - logError(error, 'Error while processing route: ' + transition.targetName); - }, - - loading: function(transition, originRoute) { - // Attempt to find an appropriate loading substate to enter. - var router = originRoute.router; - - var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { - var childLoadingRouteName = findChildRouteName(route, childRoute, 'loading'); - - if (childLoadingRouteName) { - router.intermediateTransitionTo(childLoadingRouteName); - return; - } - - // Don't bubble above pivot route. - if (transition.pivotHandler !== route) { - return true; - } - }); - - if (tryTopLevel) { - // Check for top-level loading state to enter. - if (routeHasBeenDefined(originRoute.router, 'application_loading')) { - router.intermediateTransitionTo('application_loading'); - return; - } - } - } - }; - - function logError(error, initialMessage) { - var errorArgs = []; - - if (initialMessage) { errorArgs.push(initialMessage); } - - if (error) { - if (error.message) { errorArgs.push(error.message); } - if (error.stack) { errorArgs.push(error.stack); } - - if (typeof error === "string") { errorArgs.push(error); } - } - - Ember.Logger.error.apply(this, errorArgs); - } - - function findChildRouteName(parentRoute, originatingChildRoute, name) { - var router = parentRoute.router; - var childName; - var targetChildRouteName = originatingChildRoute.routeName.split('.').pop(); - var namespace = parentRoute.routeName === 'application' ? '' : parentRoute.routeName + '.'; - - - // Second, try general loading state, e.g. 'loading' - childName = namespace + name; - if (routeHasBeenDefined(router, childName)) { - return childName; - } - } - - function routeHasBeenDefined(router, name) { - var container = router.container; - return router.hasRoute(name) && - (container.has('template:' + name) || container.has('route:' + name)); - } - - function triggerEvent(handlerInfos, ignoreFailure, args) { - var name = args.shift(); - - if (!handlerInfos) { - if (ignoreFailure) { return; } - throw new EmberError("Can't trigger action '" + name + "' because your app hasn't finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call `.send()` on the `Transition` object passed to the `model/beforeModel/afterModel` hooks."); - } - - var eventWasHandled = false; - var handlerInfo, handler; - - for (var i = handlerInfos.length - 1; i >= 0; i--) { - handlerInfo = handlerInfos[i]; - handler = handlerInfo.handler; - - if (handler._actions && handler._actions[name]) { - if (handler._actions[name].apply(handler, args) === true) { - eventWasHandled = true; - } else { - return; - } - } - } - - if (defaultActionHandlers[name]) { - defaultActionHandlers[name].apply(null, args); - return; - } - - if (!eventWasHandled && !ignoreFailure) { - throw new EmberError("Nothing handled the action '" + name + "'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble."); - } - } - - function calculatePostTransitionState(emberRouter, leafRouteName, contexts) { - var routerjs = emberRouter.router; - var state = routerjs.applyIntent(leafRouteName, contexts); - var handlerInfos = state.handlerInfos; - var params = state.params; - - for (var i = 0, len = handlerInfos.length; i < len; ++i) { - var handlerInfo = handlerInfos[i]; - if (!handlerInfo.isResolved) { - handlerInfo = handlerInfo.becomeResolved(null, handlerInfo.context); - } - params[handlerInfo.name] = handlerInfo.params; - } - return state; - } - - function updatePaths(router) { - var appController = router.container.lookup('controller:application'); - - if (!appController) { - // appController might not exist when top-level loading/error - // substates have been entered since ApplicationRoute hasn't - // actually been entered at that point. - return; - } - - var infos = router.router.currentHandlerInfos; - var path = EmberRouter._routePath(infos); - - if (!('currentPath' in appController)) { - defineProperty(appController, 'currentPath'); - } - - set(appController, 'currentPath', path); - - if (!('currentRouteName' in appController)) { - defineProperty(appController, 'currentRouteName'); - } - - set(appController, 'currentRouteName', infos[infos.length - 1].name); - } - - EmberRouter.reopenClass({ - router: null, - - /** - The `Router.map` function allows you to define mappings from URLs to routes - and resources in your application. These mappings are defined within the - supplied callback function using `this.resource` and `this.route`. - - ```javascript - App.Router.map(function({ - this.route('about'); - this.resource('article'); - })); - ``` - - For more detailed examples please see - [the guides](http://emberjs.com/guides/routing/defining-your-routes/). - - @method map - @param callback - */ - map: function(callback) { - var router = this.router; - if (!router) { - router = new Router(); - - - router._triggerWillChangeContext = K; - router._triggerWillLeave = K; - - - router.callbacks = []; - router.triggerEvent = triggerEvent; - this.reopenClass({ router: router }); - } - - var dsl = EmberRouterDSL.map(function() { - this.resource('application', { path: "/" }, function() { - for (var i=0; i < router.callbacks.length; i++) { - router.callbacks[i].call(this); - } - callback.call(this); - }); - }); - - router.callbacks.push(callback); - router.map(dsl.generate()); - return router; - }, - - _routePath: function(handlerInfos) { - var path = []; - - // We have to handle coalescing resource names that - // are prefixed with their parent's names, e.g. - // ['foo', 'foo.bar.baz'] => 'foo.bar.baz', not 'foo.foo.bar.baz' - - function intersectionMatches(a1, a2) { - for (var i = 0, len = a1.length; i < len; ++i) { - if (a1[i] !== a2[i]) { - return false; - } - } - return true; - } - - var name, nameParts, oldNameParts; - for (var i=1, l=handlerInfos.length; i 0) - (diff < 0); - } - - /** - This will compare two javascript values of possibly different types. - It will tell you which one is greater than the other by returning: - - - -1 if the first is smaller than the second, - - 0 if both are equal, - - 1 if the first is greater than the second. - - The order is calculated based on `Ember.ORDER_DEFINITION`, if types are different. - In case they have the same type an appropriate comparison for this type is made. - - ```javascript - Ember.compare('hello', 'hello'); // 0 - Ember.compare('abc', 'dfg'); // -1 - Ember.compare(2, 1); // 1 - ``` - - @method compare - @for Ember - @param {Object} v First value to compare - @param {Object} w Second value to compare - @return {Number} -1 if v < w, 0 if v = w and 1 if v > w. - */ - __exports__["default"] = function compare(v, w) { - if (v === w) { - return 0; - } - - var type1 = typeOf(v); - var type2 = typeOf(w); - - if (Comparable) { - if (type1 === 'instance' && Comparable.detect(v) && v.constructor.compare) { - return v.constructor.compare(v, w); - } - - if (type2 === 'instance' && Comparable.detect(w) && w.constructor.compare) { - return w.constructor.compare(w, v) * -1; - } - } - - var res = spaceship(TYPE_ORDER[type1], TYPE_ORDER[type2]); - - if (res !== 0) { - return res; - } - - // types are equal - so we have to check values now - switch (type1) { - case 'boolean': - case 'number': - return spaceship(v,w); - - case 'string': - return spaceship(v.localeCompare(w), 0); - - case 'array': - var vLen = v.length; - var wLen = w.length; - var len = Math.min(vLen, wLen); - - for (var i = 0; i < len; i++) { - var r = compare(v[i], w[i]); - if (r !== 0) { - return r; - } - } - - // all elements are equal now - // shorter array should be ordered first - return spaceship(vLen, wLen); - - case 'instance': - if (Comparable && Comparable.detect(v)) { - return v.compare(v, w); - } - return 0; - - case 'date': - return spaceship(v.getTime(), w.getTime()); - - default: - return 0; - } - } - }); -enifed("ember-runtime/computed/array_computed", - ["ember-metal/core","ember-runtime/computed/reduce_computed","ember-metal/enumerable_utils","ember-metal/platform","ember-metal/observer","ember-metal/error","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var ReduceComputedProperty = __dependency2__.ReduceComputedProperty; - var forEach = __dependency3__.forEach; - var o_create = __dependency4__.create; - var addObserver = __dependency5__.addObserver; - var EmberError = __dependency6__["default"]; - - var a_slice = [].slice; - - function ArrayComputedProperty() { - var cp = this; - - ReduceComputedProperty.apply(this, arguments); - - this.func = (function(reduceFunc) { - return function (propertyName) { - if (!cp._hasInstanceMeta(this, propertyName)) { - // When we recompute an array computed property, we need already - // retrieved arrays to be updated; we can't simply empty the cache and - // hope the array is re-retrieved. - forEach(cp._dependentKeys, function(dependentKey) { - addObserver(this, dependentKey, function() { - cp.recomputeOnce.call(this, propertyName); - }); - }, this); - } - - return reduceFunc.apply(this, arguments); - }; - })(this.func); - - return this; - } - - ArrayComputedProperty.prototype = o_create(ReduceComputedProperty.prototype); - - ArrayComputedProperty.prototype.initialValue = function () { - return Ember.A(); - }; - - ArrayComputedProperty.prototype.resetValue = function (array) { - array.clear(); - return array; - }; - - // This is a stopgap to keep the reference counts correct with lazy CPs. - ArrayComputedProperty.prototype.didChange = function (obj, keyName) { - return; - }; - - /** - Creates a computed property which operates on dependent arrays and - is updated with "one at a time" semantics. When items are added or - removed from the dependent array(s) an array computed only operates - on the change instead of re-evaluating the entire array. This should - return an array, if you'd like to use "one at a time" semantics and - compute some value other then an array look at - `Ember.reduceComputed`. - - If there are more than one arguments the first arguments are - considered to be dependent property keys. The last argument is - required to be an options object. The options object can have the - following three properties. - - `initialize` - An optional initialize function. Typically this will be used - to set up state on the instanceMeta object. - - `removedItem` - A function that is called each time an element is - removed from the array. - - `addedItem` - A function that is called each time an element is - added to the array. - - - The `initialize` function has the following signature: - - ```javascript - function(array, changeMeta, instanceMeta) - ``` - - `array` - The initial value of the arrayComputed, an empty array. - - `changeMeta` - An object which contains meta information about the - computed. It contains the following properties: - - - `property` the computed property - - `propertyName` the name of the property on the object - - `instanceMeta` - An object that can be used to store meta - information needed for calculating your computed. For example a - unique computed might use this to store the number of times a given - element is found in the dependent array. - - - The `removedItem` and `addedItem` functions both have the following signature: - - ```javascript - function(accumulatedValue, item, changeMeta, instanceMeta) - ``` - - `accumulatedValue` - The value returned from the last time - `removedItem` or `addedItem` was called or an empty array. - - `item` - the element added or removed from the array - - `changeMeta` - An object which contains meta information about the - change. It contains the following properties: - - - `property` the computed property - - `propertyName` the name of the property on the object - - `index` the index of the added or removed item - - `item` the added or removed item: this is exactly the same as - the second arg - - `arrayChanged` the array that triggered the change. Can be - useful when depending on multiple arrays. - - For property changes triggered on an item property change (when - depKey is something like `someArray.@each.someProperty`), - `changeMeta` will also contain the following property: - - - `previousValues` an object whose keys are the properties that changed on - the item, and whose values are the item's previous values. - - `previousValues` is important Ember coalesces item property changes via - Ember.run.once. This means that by the time removedItem gets called, item has - the new values, but you may need the previous value (eg for sorting & - filtering). - - `instanceMeta` - An object that can be used to store meta - information needed for calculating your computed. For example a - unique computed might use this to store the number of times a given - element is found in the dependent array. - - The `removedItem` and `addedItem` functions should return the accumulated - value. It is acceptable to not return anything (ie return undefined) - to invalidate the computation. This is generally not a good idea for - arrayComputed but it's used in eg max and min. - - Example - - ```javascript - Ember.computed.map = function(dependentKey, callback) { - var options = { - addedItem: function(array, item, changeMeta, instanceMeta) { - var mapped = callback(item); - array.insertAt(changeMeta.index, mapped); - return array; - }, - removedItem: function(array, item, changeMeta, instanceMeta) { - array.removeAt(changeMeta.index, 1); - return array; - } - }; - - return Ember.arrayComputed(dependentKey, options); - }; - ``` - - @method arrayComputed - @for Ember - @param {String} [dependentKeys*] - @param {Object} options - @return {Ember.ComputedProperty} - */ - function arrayComputed (options) { - var args; - - if (arguments.length > 1) { - args = a_slice.call(arguments, 0, -1); - options = a_slice.call(arguments, -1)[0]; - } - - if (typeof options !== 'object') { - throw new EmberError('Array Computed Property declared without an options hash'); - } - - var cp = new ArrayComputedProperty(options); - - if (args) { - cp.property.apply(cp, args); - } - - return cp; - } - - __exports__.arrayComputed = arrayComputed; - __exports__.ArrayComputedProperty = ArrayComputedProperty; - }); -enifed("ember-runtime/computed/reduce_computed", - ["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/error","ember-metal/property_events","ember-metal/expand_properties","ember-metal/observer","ember-metal/computed","ember-metal/platform","ember-metal/enumerable_utils","ember-runtime/system/tracked_array","ember-runtime/mixins/array","ember-metal/run_loop","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - var e_get = __dependency2__.get; - var guidFor = __dependency3__.guidFor; - var metaFor = __dependency3__.meta; - var EmberError = __dependency4__["default"]; - var propertyWillChange = __dependency5__.propertyWillChange; - var propertyDidChange = __dependency5__.propertyDidChange; - var expandProperties = __dependency6__["default"]; - var addObserver = __dependency7__.addObserver; - var removeObserver = __dependency7__.removeObserver; - var addBeforeObserver = __dependency7__.addBeforeObserver; - var removeBeforeObserver = __dependency7__.removeBeforeObserver; - var ComputedProperty = __dependency8__.ComputedProperty; - var cacheFor = __dependency8__.cacheFor; - var o_create = __dependency9__.create; - var forEach = __dependency10__.forEach; - var TrackedArray = __dependency11__["default"]; - var EmberArray = __dependency12__["default"]; - var run = __dependency13__["default"]; - var isArray = __dependency3__.isArray; - - var cacheSet = cacheFor.set; - var cacheGet = cacheFor.get; - var cacheRemove = cacheFor.remove; - var a_slice = [].slice; - // Here we explicitly don't allow `@each.foo`; it would require some special - // testing, but there's no particular reason why it should be disallowed. - var eachPropertyPattern = /^(.*)\.@each\.(.*)/; - var doubleEachPropertyPattern = /(.*\.@each){2,}/; - var arrayBracketPattern = /\.\[\]$/; - - function get(obj, key) { - if (key === '@this') { - return obj; - } - - return e_get(obj, key); - } - - /* - Tracks changes to dependent arrays, as well as to properties of items in - dependent arrays. - - @class DependentArraysObserver - */ - function DependentArraysObserver(callbacks, cp, instanceMeta, context, propertyName, sugarMeta) { - // user specified callbacks for `addedItem` and `removedItem` - this.callbacks = callbacks; - - // the computed property: remember these are shared across instances - this.cp = cp; - - // the ReduceComputedPropertyInstanceMeta this DependentArraysObserver is - // associated with - this.instanceMeta = instanceMeta; - - // A map of array guids to dependentKeys, for the given context. We track - // this because we want to set up the computed property potentially before the - // dependent array even exists, but when the array observer fires, we lack - // enough context to know what to update: we can recover that context by - // getting the dependentKey. - this.dependentKeysByGuid = {}; - - // a map of dependent array guids -> TrackedArray instances. We use - // this to lazily recompute indexes for item property observers. - this.trackedArraysByGuid = {}; - - // We suspend observers to ignore replacements from `reset` when totally - // recomputing. Unfortunately we cannot properly suspend the observers - // because we only have the key; instead we make the observers no-ops - this.suspended = false; - - // This is used to coalesce item changes from property observers within a - // single item. - this.changedItems = {}; - // This is used to coalesce item changes for multiple items that depend on - // some shared state. - this.changedItemCount = 0; - } - - function ItemPropertyObserverContext (dependentArray, index, trackedArray) { - Ember.assert('Internal error: trackedArray is null or undefined', trackedArray); - - this.dependentArray = dependentArray; - this.index = index; - this.item = dependentArray.objectAt(index); - this.trackedArray = trackedArray; - this.beforeObserver = null; - this.observer = null; - this.destroyed = false; - } - - DependentArraysObserver.prototype = { - setValue: function (newValue) { - this.instanceMeta.setValue(newValue, true); - }, - - getValue: function () { - return this.instanceMeta.getValue(); - }, - - setupObservers: function (dependentArray, dependentKey) { - this.dependentKeysByGuid[guidFor(dependentArray)] = dependentKey; - - dependentArray.addArrayObserver(this, { - willChange: 'dependentArrayWillChange', - didChange: 'dependentArrayDidChange' - }); - - if (this.cp._itemPropertyKeys[dependentKey]) { - this.setupPropertyObservers(dependentKey, this.cp._itemPropertyKeys[dependentKey]); - } - }, - - teardownObservers: function (dependentArray, dependentKey) { - var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || []; - - delete this.dependentKeysByGuid[guidFor(dependentArray)]; - - this.teardownPropertyObservers(dependentKey, itemPropertyKeys); - - dependentArray.removeArrayObserver(this, { - willChange: 'dependentArrayWillChange', - didChange: 'dependentArrayDidChange' - }); - }, - - suspendArrayObservers: function (callback, binding) { - var oldSuspended = this.suspended; - this.suspended = true; - callback.call(binding); - this.suspended = oldSuspended; - }, - - setupPropertyObservers: function (dependentKey, itemPropertyKeys) { - var dependentArray = get(this.instanceMeta.context, dependentKey); - var length = get(dependentArray, 'length'); - var observerContexts = new Array(length); - - this.resetTransformations(dependentKey, observerContexts); - - forEach(dependentArray, function (item, index) { - var observerContext = this.createPropertyObserverContext(dependentArray, index, this.trackedArraysByGuid[dependentKey]); - observerContexts[index] = observerContext; - - forEach(itemPropertyKeys, function (propertyKey) { - addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); - addObserver(item, propertyKey, this, observerContext.observer); - }, this); - }, this); - }, - - teardownPropertyObservers: function (dependentKey, itemPropertyKeys) { - var dependentArrayObserver = this; - var trackedArray = this.trackedArraysByGuid[dependentKey]; - var beforeObserver, observer, item; - - if (!trackedArray) { return; } - - trackedArray.apply(function (observerContexts, offset, operation) { - if (operation === TrackedArray.DELETE) { return; } - - forEach(observerContexts, function (observerContext) { - observerContext.destroyed = true; - beforeObserver = observerContext.beforeObserver; - observer = observerContext.observer; - item = observerContext.item; - - forEach(itemPropertyKeys, function (propertyKey) { - removeBeforeObserver(item, propertyKey, dependentArrayObserver, beforeObserver); - removeObserver(item, propertyKey, dependentArrayObserver, observer); - }); - }); - }); - }, - - createPropertyObserverContext: function (dependentArray, index, trackedArray) { - var observerContext = new ItemPropertyObserverContext(dependentArray, index, trackedArray); - - this.createPropertyObserver(observerContext); - - return observerContext; - }, - - createPropertyObserver: function (observerContext) { - var dependentArrayObserver = this; - - observerContext.beforeObserver = function (obj, keyName) { - return dependentArrayObserver.itemPropertyWillChange(obj, keyName, observerContext.dependentArray, observerContext); - }; - - observerContext.observer = function (obj, keyName) { - return dependentArrayObserver.itemPropertyDidChange(obj, keyName, observerContext.dependentArray, observerContext); - }; - }, - - resetTransformations: function (dependentKey, observerContexts) { - this.trackedArraysByGuid[dependentKey] = new TrackedArray(observerContexts); - }, - - trackAdd: function (dependentKey, index, newItems) { - var trackedArray = this.trackedArraysByGuid[dependentKey]; - - if (trackedArray) { - trackedArray.addItems(index, newItems); - } - }, - - trackRemove: function (dependentKey, index, removedCount) { - var trackedArray = this.trackedArraysByGuid[dependentKey]; - - if (trackedArray) { - return trackedArray.removeItems(index, removedCount); - } - - return []; - }, - - updateIndexes: function (trackedArray, array) { - var length = get(array, 'length'); - // OPTIMIZE: we could stop updating once we hit the object whose observer - // fired; ie partially apply the transformations - trackedArray.apply(function (observerContexts, offset, operation, operationIndex) { - // we don't even have observer contexts for removed items, even if we did, - // they no longer have any index in the array - if (operation === TrackedArray.DELETE) { return; } - if (operationIndex === 0 && operation === TrackedArray.RETAIN && observerContexts.length === length && offset === 0) { - // If we update many items we don't want to walk the array each time: we - // only need to update the indexes at most once per run loop. - return; - } - - forEach(observerContexts, function (context, index) { - context.index = index + offset; - }); - }); - }, - - dependentArrayWillChange: function (dependentArray, index, removedCount, addedCount) { - if (this.suspended) { return; } - - var removedItem = this.callbacks.removedItem; - var changeMeta; - var guid = guidFor(dependentArray); - var dependentKey = this.dependentKeysByGuid[guid]; - var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || []; - var length = get(dependentArray, 'length'); - var normalizedIndex = normalizeIndex(index, length, 0); - var normalizedRemoveCount = normalizeRemoveCount(normalizedIndex, length, removedCount); - var item, itemIndex, sliceIndex, observerContexts; - - observerContexts = this.trackRemove(dependentKey, normalizedIndex, normalizedRemoveCount); - - function removeObservers(propertyKey) { - observerContexts[sliceIndex].destroyed = true; - removeBeforeObserver(item, propertyKey, this, observerContexts[sliceIndex].beforeObserver); - removeObserver(item, propertyKey, this, observerContexts[sliceIndex].observer); - } - - for (sliceIndex = normalizedRemoveCount - 1; sliceIndex >= 0; --sliceIndex) { - itemIndex = normalizedIndex + sliceIndex; - if (itemIndex >= length) { break; } - - item = dependentArray.objectAt(itemIndex); - - forEach(itemPropertyKeys, removeObservers, this); - - changeMeta = new ChangeMeta(dependentArray, item, itemIndex, this.instanceMeta.propertyName, this.cp, normalizedRemoveCount); - this.setValue(removedItem.call( - this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); - } - this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); - }, - - dependentArrayDidChange: function (dependentArray, index, removedCount, addedCount) { - if (this.suspended) { return; } - - var addedItem = this.callbacks.addedItem; - var guid = guidFor(dependentArray); - var dependentKey = this.dependentKeysByGuid[guid]; - var observerContexts = new Array(addedCount); - var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey]; - var length = get(dependentArray, 'length'); - var normalizedIndex = normalizeIndex(index, length, addedCount); - var endIndex = normalizedIndex + addedCount; - var changeMeta, observerContext; - - forEach(dependentArray.slice(normalizedIndex, endIndex), function (item, sliceIndex) { - if (itemPropertyKeys) { - observerContext = this.createPropertyObserverContext(dependentArray, normalizedIndex + sliceIndex, - this.trackedArraysByGuid[dependentKey]); - observerContexts[sliceIndex] = observerContext; - - forEach(itemPropertyKeys, function (propertyKey) { - addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); - addObserver(item, propertyKey, this, observerContext.observer); - }, this); - } - - changeMeta = new ChangeMeta(dependentArray, item, normalizedIndex + sliceIndex, this.instanceMeta.propertyName, this.cp, addedCount); - this.setValue(addedItem.call( - this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); - }, this); - this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); - this.trackAdd(dependentKey, normalizedIndex, observerContexts); - }, - - itemPropertyWillChange: function (obj, keyName, array, observerContext) { - var guid = guidFor(obj); - - if (!this.changedItems[guid]) { - this.changedItems[guid] = { - array: array, - observerContext: observerContext, - obj: obj, - previousValues: {} - }; - } - - ++this.changedItemCount; - this.changedItems[guid].previousValues[keyName] = get(obj, keyName); - }, - - itemPropertyDidChange: function (obj, keyName, array, observerContext) { - if (--this.changedItemCount === 0) { - this.flushChanges(); - } - }, - - flushChanges: function () { - var changedItems = this.changedItems; - var key, c, changeMeta; - - for (key in changedItems) { - c = changedItems[key]; - if (c.observerContext.destroyed) { continue; } - - this.updateIndexes(c.observerContext.trackedArray, c.observerContext.dependentArray); - - changeMeta = new ChangeMeta(c.array, c.obj, c.observerContext.index, this.instanceMeta.propertyName, this.cp, changedItems.length, c.previousValues); - this.setValue( - this.callbacks.removedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); - this.setValue( - this.callbacks.addedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); - } - - this.changedItems = {}; - this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); - } - }; - - function normalizeIndex(index, length, newItemsOffset) { - if (index < 0) { - return Math.max(0, length + index); - } else if (index < length) { - return index; - } else /* index > length */ { - return Math.min(length - newItemsOffset, index); - } - } - - function normalizeRemoveCount(index, length, removedCount) { - return Math.min(removedCount, length - index); - } - - function ChangeMeta(dependentArray, item, index, propertyName, property, changedCount, previousValues){ - this.arrayChanged = dependentArray; - this.index = index; - this.item = item; - this.propertyName = propertyName; - this.property = property; - this.changedCount = changedCount; - - if (previousValues) { - // previous values only available for item property changes - this.previousValues = previousValues; - } - } - - function addItems(dependentArray, callbacks, cp, propertyName, meta) { - forEach(dependentArray, function (item, index) { - meta.setValue( callbacks.addedItem.call( - this, meta.getValue(), item, new ChangeMeta(dependentArray, item, index, propertyName, cp, dependentArray.length), meta.sugarMeta)); - }, this); - callbacks.flushedChanges.call(this, meta.getValue(), meta.sugarMeta); - } - - function reset(cp, propertyName) { - var hadMeta = cp._hasInstanceMeta(this, propertyName); - var meta = cp._instanceMeta(this, propertyName); - - if (hadMeta) { meta.setValue(cp.resetValue(meta.getValue())); } - - if (cp.options.initialize) { - cp.options.initialize.call(this, meta.getValue(), { - property: cp, - propertyName: propertyName - }, meta.sugarMeta); - } - } - - function partiallyRecomputeFor(obj, dependentKey) { - if (arrayBracketPattern.test(dependentKey)) { - return false; - } - - var value = get(obj, dependentKey); - return EmberArray.detect(value); - } - - function ReduceComputedPropertyInstanceMeta(context, propertyName, initialValue) { - this.context = context; - this.propertyName = propertyName; - this.cache = metaFor(context).cache; - this.dependentArrays = {}; - this.sugarMeta = {}; - this.initialValue = initialValue; - } - - ReduceComputedPropertyInstanceMeta.prototype = { - getValue: function () { - var value = cacheGet(this.cache, this.propertyName); - - if (value !== undefined) { - return value; - } else { - return this.initialValue; - } - }, - - setValue: function(newValue, triggerObservers) { - // This lets sugars force a recomputation, handy for very simple - // implementations of eg max. - if (newValue === cacheGet(this.cache, this.propertyName)) { - return; - } - - if (triggerObservers) { - propertyWillChange(this.context, this.propertyName); - } - - if (newValue === undefined) { - cacheRemove(this.cache, this.propertyName); - } else { - cacheSet(this.cache, this.propertyName, newValue); - } - - if (triggerObservers) { - propertyDidChange(this.context, this.propertyName); - } - } - }; - - /** - A computed property whose dependent keys are arrays and which is updated with - "one at a time" semantics. - - @class ReduceComputedProperty - @namespace Ember - @extends Ember.ComputedProperty - @constructor - */ - - __exports__.ReduceComputedProperty = ReduceComputedProperty; - // TODO: default export - - function ReduceComputedProperty(options) { - var cp = this; - - this.options = options; - this._dependentKeys = null; - this._cacheable = true; - // A map of dependentKey -> [itemProperty, ...] that tracks what properties of - // items in the array we must track to update this property. - this._itemPropertyKeys = {}; - this._previousItemPropertyKeys = {}; - - this.readOnly(); - - this.recomputeOnce = function(propertyName) { - // What we really want to do is coalesce by . - // We need a form of `scheduleOnce` that accepts an arbitrary token to - // coalesce by, in addition to the target and method. - run.once(this, recompute, propertyName); - }; - - var recompute = function(propertyName) { - var meta = cp._instanceMeta(this, propertyName); - var callbacks = cp._callbacks(); - - reset.call(this, cp, propertyName); - - meta.dependentArraysObserver.suspendArrayObservers(function () { - forEach(cp._dependentKeys, function (dependentKey) { - Ember.assert( - 'dependent array ' + dependentKey + ' must be an `Ember.Array`. ' + - 'If you are not extending arrays, you will need to wrap native arrays with `Ember.A`', - !(isArray(get(this, dependentKey)) && !EmberArray.detect(get(this, dependentKey)))); - - if (!partiallyRecomputeFor(this, dependentKey)) { return; } - - var dependentArray = get(this, dependentKey); - var previousDependentArray = meta.dependentArrays[dependentKey]; - - if (dependentArray === previousDependentArray) { - // The array may be the same, but our item property keys may have - // changed, so we set them up again. We can't easily tell if they've - // changed: the array may be the same object, but with different - // contents. - if (cp._previousItemPropertyKeys[dependentKey]) { - delete cp._previousItemPropertyKeys[dependentKey]; - meta.dependentArraysObserver.setupPropertyObservers(dependentKey, cp._itemPropertyKeys[dependentKey]); - } - } else { - meta.dependentArrays[dependentKey] = dependentArray; - - if (previousDependentArray) { - meta.dependentArraysObserver.teardownObservers(previousDependentArray, dependentKey); - } - - if (dependentArray) { - meta.dependentArraysObserver.setupObservers(dependentArray, dependentKey); - } - } - }, this); - }, this); - - forEach(cp._dependentKeys, function(dependentKey) { - if (!partiallyRecomputeFor(this, dependentKey)) { return; } - - var dependentArray = get(this, dependentKey); - - if (dependentArray) { - addItems.call(this, dependentArray, callbacks, cp, propertyName, meta); - } - }, this); - }; - - - this.func = function (propertyName) { - Ember.assert('Computed reduce values require at least one dependent key', cp._dependentKeys); - - recompute.call(this, propertyName); - - return cp._instanceMeta(this, propertyName).getValue(); - }; - } - - ReduceComputedProperty.prototype = o_create(ComputedProperty.prototype); - - function defaultCallback(computedValue) { - return computedValue; - } - - ReduceComputedProperty.prototype._callbacks = function () { - if (!this.callbacks) { - var options = this.options; - - this.callbacks = { - removedItem: options.removedItem || defaultCallback, - addedItem: options.addedItem || defaultCallback, - flushedChanges: options.flushedChanges || defaultCallback - }; - } - - return this.callbacks; - }; - - ReduceComputedProperty.prototype._hasInstanceMeta = function (context, propertyName) { - return !!metaFor(context).cacheMeta[propertyName]; - }; - - ReduceComputedProperty.prototype._instanceMeta = function (context, propertyName) { - var cacheMeta = metaFor(context).cacheMeta; - var meta = cacheMeta[propertyName]; - - if (!meta) { - meta = cacheMeta[propertyName] = new ReduceComputedPropertyInstanceMeta(context, propertyName, this.initialValue()); - meta.dependentArraysObserver = new DependentArraysObserver(this._callbacks(), this, meta, context, propertyName, meta.sugarMeta); - } - - return meta; - }; - - ReduceComputedProperty.prototype.initialValue = function () { - if (typeof this.options.initialValue === 'function') { - return this.options.initialValue(); - } - else { - return this.options.initialValue; - } - }; - - ReduceComputedProperty.prototype.resetValue = function (value) { - return this.initialValue(); - }; - - ReduceComputedProperty.prototype.itemPropertyKey = function (dependentArrayKey, itemPropertyKey) { - this._itemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey] || []; - this._itemPropertyKeys[dependentArrayKey].push(itemPropertyKey); - }; - - ReduceComputedProperty.prototype.clearItemPropertyKeys = function (dependentArrayKey) { - if (this._itemPropertyKeys[dependentArrayKey]) { - this._previousItemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey]; - this._itemPropertyKeys[dependentArrayKey] = []; - } - }; - - ReduceComputedProperty.prototype.property = function () { - var cp = this; - var args = a_slice.call(arguments); - var propertyArgs = {}; - var match, dependentArrayKey; - - forEach(args, function (dependentKey) { - if (doubleEachPropertyPattern.test(dependentKey)) { - throw new EmberError('Nested @each properties not supported: ' + dependentKey); - } else if (match = eachPropertyPattern.exec(dependentKey)) { - dependentArrayKey = match[1]; - - var itemPropertyKeyPattern = match[2]; - var addItemPropertyKey = function (itemPropertyKey) { - cp.itemPropertyKey(dependentArrayKey, itemPropertyKey); - }; - - expandProperties(itemPropertyKeyPattern, addItemPropertyKey); - propertyArgs[guidFor(dependentArrayKey)] = dependentArrayKey; - } else { - propertyArgs[guidFor(dependentKey)] = dependentKey; - } - }); - - var propertyArgsToArray = []; - for (var guid in propertyArgs) { - propertyArgsToArray.push(propertyArgs[guid]); - } - - return ComputedProperty.prototype.property.apply(this, propertyArgsToArray); - }; - - /** - Creates a computed property which operates on dependent arrays and - is updated with "one at a time" semantics. When items are added or - removed from the dependent array(s) a reduce computed only operates - on the change instead of re-evaluating the entire array. - - If there are more than one arguments the first arguments are - considered to be dependent property keys. The last argument is - required to be an options object. The options object can have the - following four properties: - - `initialValue` - A value or function that will be used as the initial - value for the computed. If this property is a function the result of calling - the function will be used as the initial value. This property is required. - - `initialize` - An optional initialize function. Typically this will be used - to set up state on the instanceMeta object. - - `removedItem` - A function that is called each time an element is removed - from the array. - - `addedItem` - A function that is called each time an element is added to - the array. - - - The `initialize` function has the following signature: - - ```javascript - function(initialValue, changeMeta, instanceMeta) - ``` - - `initialValue` - The value of the `initialValue` property from the - options object. - - `changeMeta` - An object which contains meta information about the - computed. It contains the following properties: - - - `property` the computed property - - `propertyName` the name of the property on the object - - `instanceMeta` - An object that can be used to store meta - information needed for calculating your computed. For example a - unique computed might use this to store the number of times a given - element is found in the dependent array. - - - The `removedItem` and `addedItem` functions both have the following signature: - - ```javascript - function(accumulatedValue, item, changeMeta, instanceMeta) - ``` - - `accumulatedValue` - The value returned from the last time - `removedItem` or `addedItem` was called or `initialValue`. - - `item` - the element added or removed from the array - - `changeMeta` - An object which contains meta information about the - change. It contains the following properties: - - - `property` the computed property - - `propertyName` the name of the property on the object - - `index` the index of the added or removed item - - `item` the added or removed item: this is exactly the same as - the second arg - - `arrayChanged` the array that triggered the change. Can be - useful when depending on multiple arrays. - - For property changes triggered on an item property change (when - depKey is something like `someArray.@each.someProperty`), - `changeMeta` will also contain the following property: - - - `previousValues` an object whose keys are the properties that changed on - the item, and whose values are the item's previous values. - - `previousValues` is important Ember coalesces item property changes via - Ember.run.once. This means that by the time removedItem gets called, item has - the new values, but you may need the previous value (eg for sorting & - filtering). - - `instanceMeta` - An object that can be used to store meta - information needed for calculating your computed. For example a - unique computed might use this to store the number of times a given - element is found in the dependent array. - - The `removedItem` and `addedItem` functions should return the accumulated - value. It is acceptable to not return anything (ie return undefined) - to invalidate the computation. This is generally not a good idea for - arrayComputed but it's used in eg max and min. - - Note that observers will be fired if either of these functions return a value - that differs from the accumulated value. When returning an object that - mutates in response to array changes, for example an array that maps - everything from some other array (see `Ember.computed.map`), it is usually - important that the *same* array be returned to avoid accidentally triggering observers. - - Example - - ```javascript - Ember.computed.max = function(dependentKey) { - return Ember.reduceComputed(dependentKey, { - initialValue: -Infinity, - - addedItem: function(accumulatedValue, item, changeMeta, instanceMeta) { - return Math.max(accumulatedValue, item); - }, - - removedItem: function(accumulatedValue, item, changeMeta, instanceMeta) { - if (item < accumulatedValue) { - return accumulatedValue; - } - } - }); - }; - ``` - - Dependent keys may refer to `@this` to observe changes to the object itself, - which must be array-like, rather than a property of the object. This is - mostly useful for array proxies, to ensure objects are retrieved via - `objectAtContent`. This is how you could sort items by properties defined on an item controller. - - Example - - ```javascript - App.PeopleController = Ember.ArrayController.extend({ - itemController: 'person', - - sortedPeople: Ember.computed.sort('@this.@each.reversedName', function(personA, personB) { - // `reversedName` isn't defined on Person, but we have access to it via - // the item controller App.PersonController. If we'd used - // `content.@each.reversedName` above, we would be getting the objects - // directly and not have access to `reversedName`. - // - var reversedNameA = get(personA, 'reversedName'); - var reversedNameB = get(personB, 'reversedName'); - - return Ember.compare(reversedNameA, reversedNameB); - }) - }); - - App.PersonController = Ember.ObjectController.extend({ - reversedName: function() { - return reverse(get(this, 'name')); - }.property('name') - }); - ``` - - Dependent keys whose values are not arrays are treated as regular - dependencies: when they change, the computed property is completely - recalculated. It is sometimes useful to have dependent arrays with similar - semantics. Dependent keys which end in `.[]` do not use "one at a time" - semantics. When an item is added or removed from such a dependency, the - computed property is completely recomputed. - - When the computed property is completely recomputed, the `accumulatedValue` - is discarded, it starts with `initialValue` again, and each item is passed - to `addedItem` in turn. - - Example - - ```javascript - Ember.Object.extend({ - // When `string` is changed, `computed` is completely recomputed. - string: 'a string', - - // When an item is added to `array`, `addedItem` is called. - array: [], - - // When an item is added to `anotherArray`, `computed` is completely - // recomputed. - anotherArray: [], - - computed: Ember.reduceComputed('string', 'array', 'anotherArray.[]', { - addedItem: addedItemCallback, - removedItem: removedItemCallback - }) - }); - ``` - - @method reduceComputed - @for Ember - @param {String} [dependentKeys*] - @param {Object} options - @return {Ember.ComputedProperty} - */ - function reduceComputed(options) { - var args; - - if (arguments.length > 1) { - args = a_slice.call(arguments, 0, -1); - options = a_slice.call(arguments, -1)[0]; - } - - if (typeof options !== 'object') { - throw new EmberError('Reduce Computed Property declared without an options hash'); - } - - if (!('initialValue' in options)) { - throw new EmberError('Reduce Computed Property declared without an initial value'); - } - - var cp = new ReduceComputedProperty(options); - - if (args) { - cp.property.apply(cp, args); - } - - return cp; - } - - __exports__.reduceComputed = reduceComputed; - }); -enifed("ember-runtime/computed/reduce_computed_macros", - ["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/error","ember-metal/enumerable_utils","ember-metal/run_loop","ember-metal/observer","ember-runtime/computed/array_computed","ember-runtime/computed/reduce_computed","ember-runtime/system/subarray","ember-metal/keys","ember-runtime/compare","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var get = __dependency2__.get; - var isArray = __dependency3__.isArray; - var guidFor = __dependency3__.guidFor; - var EmberError = __dependency4__["default"]; - var forEach = __dependency5__.forEach; - var run = __dependency6__["default"]; - var addObserver = __dependency7__.addObserver; - var arrayComputed = __dependency8__.arrayComputed; - var reduceComputed = __dependency9__.reduceComputed; - var SubArray = __dependency10__["default"]; - var keys = __dependency11__["default"]; - var compare = __dependency12__["default"]; - - var a_slice = [].slice; - - /** - A computed property that returns the sum of the value - in the dependent array. - - @method computed.sum - @for Ember - @param {String} dependentKey - @return {Ember.ComputedProperty} computes the sum of all values in the dependentKey's array - @since 1.4.0 - */ - - function sum(dependentKey){ - return reduceComputed(dependentKey, { - initialValue: 0, - - addedItem: function(accumulatedValue, item, changeMeta, instanceMeta){ - return accumulatedValue + item; - }, - - removedItem: function(accumulatedValue, item, changeMeta, instanceMeta){ - return accumulatedValue - item; - } - }); - } - - __exports__.sum = sum;/** - A computed property that calculates the maximum value in the - dependent array. This will return `-Infinity` when the dependent - array is empty. - - ```javascript - var Person = Ember.Object.extend({ - childAges: Ember.computed.mapBy('children', 'age'), - maxChildAge: Ember.computed.max('childAges') - }); - - var lordByron = Person.create({ children: [] }); - - lordByron.get('maxChildAge'); // -Infinity - lordByron.get('children').pushObject({ - name: 'Augusta Ada Byron', age: 7 - }); - lordByron.get('maxChildAge'); // 7 - lordByron.get('children').pushObjects([{ - name: 'Allegra Byron', - age: 5 - }, { - name: 'Elizabeth Medora Leigh', - age: 8 - }]); - lordByron.get('maxChildAge'); // 8 - ``` - - @method computed.max - @for Ember - @param {String} dependentKey - @return {Ember.ComputedProperty} computes the largest value in the dependentKey's array - */ - function max(dependentKey) { - return reduceComputed(dependentKey, { - initialValue: -Infinity, - - addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { - return Math.max(accumulatedValue, item); - }, - - removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { - if (item < accumulatedValue) { - return accumulatedValue; - } - } - }); - } - - __exports__.max = max;/** - A computed property that calculates the minimum value in the - dependent array. This will return `Infinity` when the dependent - array is empty. - - ```javascript - var Person = Ember.Object.extend({ - childAges: Ember.computed.mapBy('children', 'age'), - minChildAge: Ember.computed.min('childAges') - }); - - var lordByron = Person.create({ children: [] }); - - lordByron.get('minChildAge'); // Infinity - lordByron.get('children').pushObject({ - name: 'Augusta Ada Byron', age: 7 - }); - lordByron.get('minChildAge'); // 7 - lordByron.get('children').pushObjects([{ - name: 'Allegra Byron', - age: 5 - }, { - name: 'Elizabeth Medora Leigh', - age: 8 - }]); - lordByron.get('minChildAge'); // 5 - ``` - - @method computed.min - @for Ember - @param {String} dependentKey - @return {Ember.ComputedProperty} computes the smallest value in the dependentKey's array - */ - function min(dependentKey) { - return reduceComputed(dependentKey, { - initialValue: Infinity, - - addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { - return Math.min(accumulatedValue, item); - }, - - removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { - if (item > accumulatedValue) { - return accumulatedValue; - } - } - }); - } - - __exports__.min = min;/** - Returns an array mapped via the callback - - The callback method you provide should have the following signature. - `item` is the current item in the iteration. - `index` is the integer index of the current item in the iteration. - - ```javascript - function(item, index); - ``` - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - excitingChores: Ember.computed.map('chores', function(chore, index) { - return chore.toUpperCase() + '!'; - }) - }); - - var hamster = Hamster.create({ - chores: ['clean', 'write more unit tests'] - }); - - hamster.get('excitingChores'); // ['CLEAN!', 'WRITE MORE UNIT TESTS!'] - ``` - - @method computed.map - @for Ember - @param {String} dependentKey - @param {Function} callback - @return {Ember.ComputedProperty} an array mapped via the callback - */ - function map(dependentKey, callback) { - var options = { - addedItem: function(array, item, changeMeta, instanceMeta) { - var mapped = callback.call(this, item, changeMeta.index); - array.insertAt(changeMeta.index, mapped); - return array; - }, - removedItem: function(array, item, changeMeta, instanceMeta) { - array.removeAt(changeMeta.index, 1); - return array; - } - }; - - return arrayComputed(dependentKey, options); - } - - __exports__.map = map;/** - Returns an array mapped to the specified key. - - ```javascript - var Person = Ember.Object.extend({ - childAges: Ember.computed.mapBy('children', 'age') - }); - - var lordByron = Person.create({ children: [] }); - - lordByron.get('childAges'); // [] - lordByron.get('children').pushObject({ name: 'Augusta Ada Byron', age: 7 }); - lordByron.get('childAges'); // [7] - lordByron.get('children').pushObjects([{ - name: 'Allegra Byron', - age: 5 - }, { - name: 'Elizabeth Medora Leigh', - age: 8 - }]); - lordByron.get('childAges'); // [7, 5, 8] - ``` - - @method computed.mapBy - @for Ember - @param {String} dependentKey - @param {String} propertyKey - @return {Ember.ComputedProperty} an array mapped to the specified key - */ - function mapBy (dependentKey, propertyKey) { - var callback = function(item) { return get(item, propertyKey); }; - return map(dependentKey + '.@each.' + propertyKey, callback); - } - - __exports__.mapBy = mapBy;/** - @method computed.mapProperty - @for Ember - @deprecated Use `Ember.computed.mapBy` instead - @param dependentKey - @param propertyKey - */ - var mapProperty = mapBy; - __exports__.mapProperty = mapProperty; - /** - Filters the array by the callback. - - The callback method you provide should have the following signature. - `item` is the current item in the iteration. - `index` is the integer index of the current item in the iteration. - `array` is the dependant array itself. - - ```javascript - function(item, index, array); - ``` - - ```javascript - var Hamster = Ember.Object.extend({ - remainingChores: Ember.computed.filter('chores', function(chore, index, array) { - return !chore.done; - }) - }); - - var hamster = Hamster.create({ - chores: [ - { name: 'cook', done: true }, - { name: 'clean', done: true }, - { name: 'write more unit tests', done: false } - ] - }); - - hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] - ``` - - @method computed.filter - @for Ember - @param {String} dependentKey - @param {Function} callback - @return {Ember.ComputedProperty} the filtered array - */ - function filter(dependentKey, callback) { - var options = { - initialize: function (array, changeMeta, instanceMeta) { - instanceMeta.filteredArrayIndexes = new SubArray(); - }, - - addedItem: function (array, item, changeMeta, instanceMeta) { - var match = !!callback.call(this, item, changeMeta.index, changeMeta.arrayChanged); - var filterIndex = instanceMeta.filteredArrayIndexes.addItem(changeMeta.index, match); - - if (match) { - array.insertAt(filterIndex, item); - } - - return array; - }, - - removedItem: function(array, item, changeMeta, instanceMeta) { - var filterIndex = instanceMeta.filteredArrayIndexes.removeItem(changeMeta.index); - - if (filterIndex > -1) { - array.removeAt(filterIndex); - } - - return array; - } - }; - - return arrayComputed(dependentKey, options); - } - - __exports__.filter = filter;/** - Filters the array by the property and value - - ```javascript - var Hamster = Ember.Object.extend({ - remainingChores: Ember.computed.filterBy('chores', 'done', false) - }); - - var hamster = Hamster.create({ - chores: [ - { name: 'cook', done: true }, - { name: 'clean', done: true }, - { name: 'write more unit tests', done: false } - ] - }); - - hamster.get('remainingChores'); // [{ name: 'write more unit tests', done: false }] - ``` - - @method computed.filterBy - @for Ember - @param {String} dependentKey - @param {String} propertyKey - @param {*} value - @return {Ember.ComputedProperty} the filtered array - */ - function filterBy (dependentKey, propertyKey, value) { - var callback; - - if (arguments.length === 2) { - callback = function(item) { - return get(item, propertyKey); - }; - } else { - callback = function(item) { - return get(item, propertyKey) === value; - }; - } - - return filter(dependentKey + '.@each.' + propertyKey, callback); - } - - __exports__.filterBy = filterBy;/** - @method computed.filterProperty - @for Ember - @param dependentKey - @param propertyKey - @param value - @deprecated Use `Ember.computed.filterBy` instead - */ - var filterProperty = filterBy; - __exports__.filterProperty = filterProperty; - /** - A computed property which returns a new array with all the unique - elements from one or more dependent arrays. - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - uniqueFruits: Ember.computed.uniq('fruits') - }); - - var hamster = Hamster.create({ - fruits: [ - 'banana', - 'grape', - 'kale', - 'banana' - ] - }); - - hamster.get('uniqueFruits'); // ['banana', 'grape', 'kale'] - ``` - - @method computed.uniq - @for Ember - @param {String} propertyKey* - @return {Ember.ComputedProperty} computes a new array with all the - unique elements from the dependent array - */ - function uniq() { - var args = a_slice.call(arguments); - - args.push({ - initialize: function(array, changeMeta, instanceMeta) { - instanceMeta.itemCounts = {}; - }, - - addedItem: function(array, item, changeMeta, instanceMeta) { - var guid = guidFor(item); - - if (!instanceMeta.itemCounts[guid]) { - instanceMeta.itemCounts[guid] = 1; - array.pushObject(item); - } else { - ++instanceMeta.itemCounts[guid]; - } - return array; - }, - - removedItem: function(array, item, _, instanceMeta) { - var guid = guidFor(item); - var itemCounts = instanceMeta.itemCounts; - - if (--itemCounts[guid] === 0) { - array.removeObject(item); - } - - return array; - } - }); - - return arrayComputed.apply(null, args); - } - - __exports__.uniq = uniq;/** - Alias for [Ember.computed.uniq](/api/#method_computed_uniq). - - @method computed.union - @for Ember - @param {String} propertyKey* - @return {Ember.ComputedProperty} computes a new array with all the - unique elements from the dependent array - */ - var union = uniq; - __exports__.union = union; - /** - A computed property which returns a new array with all the duplicated - elements from two or more dependent arrays. - - Example - - ```javascript - var obj = Ember.Object.createWithMixins({ - adaFriends: ['Charles Babbage', 'John Hobhouse', 'William King', 'Mary Somerville'], - charlesFriends: ['William King', 'Mary Somerville', 'Ada Lovelace', 'George Peacock'], - friendsInCommon: Ember.computed.intersect('adaFriends', 'charlesFriends') - }); - - obj.get('friendsInCommon'); // ['William King', 'Mary Somerville'] - ``` - - @method computed.intersect - @for Ember - @param {String} propertyKey* - @return {Ember.ComputedProperty} computes a new array with all the - duplicated elements from the dependent arrays - */ - function intersect() { - var args = a_slice.call(arguments); - - args.push({ - initialize: function (array, changeMeta, instanceMeta) { - instanceMeta.itemCounts = {}; - }, - - addedItem: function(array, item, changeMeta, instanceMeta) { - var itemGuid = guidFor(item); - var dependentGuid = guidFor(changeMeta.arrayChanged); - var numberOfDependentArrays = changeMeta.property._dependentKeys.length; - var itemCounts = instanceMeta.itemCounts; - - if (!itemCounts[itemGuid]) { - itemCounts[itemGuid] = {}; - } - - if (itemCounts[itemGuid][dependentGuid] === undefined) { - itemCounts[itemGuid][dependentGuid] = 0; - } - - if (++itemCounts[itemGuid][dependentGuid] === 1 && - numberOfDependentArrays === keys(itemCounts[itemGuid]).length) { - array.addObject(item); - } - - return array; - }, - - removedItem: function(array, item, changeMeta, instanceMeta) { - var itemGuid = guidFor(item); - var dependentGuid = guidFor(changeMeta.arrayChanged); - var numberOfArraysItemAppearsIn; - var itemCounts = instanceMeta.itemCounts; - - if (itemCounts[itemGuid][dependentGuid] === undefined) { - itemCounts[itemGuid][dependentGuid] = 0; - } - - if (--itemCounts[itemGuid][dependentGuid] === 0) { - delete itemCounts[itemGuid][dependentGuid]; - numberOfArraysItemAppearsIn = keys(itemCounts[itemGuid]).length; - - if (numberOfArraysItemAppearsIn === 0) { - delete itemCounts[itemGuid]; - } - - array.removeObject(item); - } - - return array; - } - }); - - return arrayComputed.apply(null, args); - } - - __exports__.intersect = intersect;/** - A computed property which returns a new array with all the - properties from the first dependent array that are not in the second - dependent array. - - Example - - ```javascript - var Hamster = Ember.Object.extend({ - likes: ['banana', 'grape', 'kale'], - wants: Ember.computed.setDiff('likes', 'fruits') - }); - - var hamster = Hamster.create({ - fruits: [ - 'grape', - 'kale', - ] - }); - - hamster.get('wants'); // ['banana'] - ``` - - @method computed.setDiff - @for Ember - @param {String} setAProperty - @param {String} setBProperty - @return {Ember.ComputedProperty} computes a new array with all the - items from the first dependent array that are not in the second - dependent array - */ - function setDiff(setAProperty, setBProperty) { - if (arguments.length !== 2) { - throw new EmberError('setDiff requires exactly two dependent arrays.'); - } - - return arrayComputed(setAProperty, setBProperty, { - addedItem: function (array, item, changeMeta, instanceMeta) { - var setA = get(this, setAProperty); - var setB = get(this, setBProperty); - - if (changeMeta.arrayChanged === setA) { - if (!setB.contains(item)) { - array.addObject(item); - } - } else { - array.removeObject(item); - } - - return array; - }, - - removedItem: function (array, item, changeMeta, instanceMeta) { - var setA = get(this, setAProperty); - var setB = get(this, setBProperty); - - if (changeMeta.arrayChanged === setB) { - if (setA.contains(item)) { - array.addObject(item); - } - } else { - array.removeObject(item); - } - - return array; - } - }); - } - - __exports__.setDiff = setDiff;function binarySearch(array, item, low, high) { - var mid, midItem, res, guidMid, guidItem; - - if (arguments.length < 4) { - high = get(array, 'length'); - } - - if (arguments.length < 3) { - low = 0; - } - - if (low === high) { - return low; - } - - mid = low + Math.floor((high - low) / 2); - midItem = array.objectAt(mid); - - guidMid = guidFor(midItem); - guidItem = guidFor(item); - - if (guidMid === guidItem) { - return mid; - } - - res = this.order(midItem, item); - - if (res === 0) { - res = guidMid < guidItem ? -1 : 1; - } - - - if (res < 0) { - return this.binarySearch(array, item, mid+1, high); - } else if (res > 0) { - return this.binarySearch(array, item, low, mid); - } - - return mid; - } - - - /** - A computed property which returns a new array with all the - properties from the first dependent array sorted based on a property - or sort function. - - The callback method you provide should have the following signature: - - ```javascript - function(itemA, itemB); - ``` - - - `itemA` the first item to compare. - - `itemB` the second item to compare. - - This function should return negative number (e.g. `-1`) when `itemA` should come before - `itemB`. It should return positive number (e.g. `1`) when `itemA` should come after - `itemB`. If the `itemA` and `itemB` are equal this function should return `0`. - - Therefore, if this function is comparing some numeric values, simple `itemA - itemB` or - `itemA.get( 'foo' ) - itemB.get( 'foo' )` can be used instead of series of `if`. - - Example - - ```javascript - var ToDoList = Ember.Object.extend({ - // using standard ascending sort - todosSorting: ['name'], - sortedTodos: Ember.computed.sort('todos', 'todosSorting'), - - // using descending sort - todosSortingDesc: ['name:desc'], - sortedTodosDesc: Ember.computed.sort('todos', 'todosSortingDesc'), - - // using a custom sort function - priorityTodos: Ember.computed.sort('todos', function(a, b){ - if (a.priority > b.priority) { - return 1; - } else if (a.priority < b.priority) { - return -1; - } - - return 0; - }) - }); - - var todoList = ToDoList.create({todos: [ - { name: 'Unit Test', priority: 2 }, - { name: 'Documentation', priority: 3 }, - { name: 'Release', priority: 1 } - ]}); - - todoList.get('sortedTodos'); // [{ name:'Documentation', priority:3 }, { name:'Release', priority:1 }, { name:'Unit Test', priority:2 }] - todoList.get('sortedTodosDesc'); // [{ name:'Unit Test', priority:2 }, { name:'Release', priority:1 }, { name:'Documentation', priority:3 }] - todoList.get('priorityTodos'); // [{ name:'Release', priority:1 }, { name:'Unit Test', priority:2 }, { name:'Documentation', priority:3 }] - ``` - - @method computed.sort - @for Ember - @param {String} dependentKey - @param {String or Function} sortDefinition a dependent key to an - array of sort properties (add `:desc` to the arrays sort properties to sort descending) or a function to use when sorting - @return {Ember.ComputedProperty} computes a new sorted array based - on the sort property array or callback function - */ - function sort(itemsKey, sortDefinition) { - Ember.assert('Ember.computed.sort requires two arguments: an array key to sort and ' + - 'either a sort properties key or sort function', arguments.length === 2); - - if (typeof sortDefinition === 'function') { - return customSort(itemsKey, sortDefinition); - } else { - return propertySort(itemsKey, sortDefinition); - } - } - - __exports__.sort = sort;function customSort(itemsKey, comparator) { - return arrayComputed(itemsKey, { - initialize: function (array, changeMeta, instanceMeta) { - instanceMeta.order = comparator; - instanceMeta.binarySearch = binarySearch; - instanceMeta.waitingInsertions = []; - instanceMeta.insertWaiting = function() { - var index, item; - var waiting = instanceMeta.waitingInsertions; - instanceMeta.waitingInsertions = []; - for (var i=0; i{{post.title}} ({{post.titleLength}} characters) - {{/each}} - ``` - - ```javascript - App.PostsController = Ember.ArrayController.extend({ - itemController: 'post' - }); - - App.PostController = Ember.ObjectController.extend({ - // the `title` property will be proxied to the underlying post. - titleLength: function() { - return this.get('title').length; - }.property('title') - }); - ``` - - In some cases it is helpful to return a different `itemController` depending - on the particular item. Subclasses can do this by overriding - `lookupItemController`. - - For example: - - ```javascript - App.MyArrayController = Ember.ArrayController.extend({ - lookupItemController: function( object ) { - if (object.get('isSpecial')) { - return "special"; // use App.SpecialController - } else { - return "regular"; // use App.RegularController - } - } - }); - ``` - - The itemController instances will have a `parentController` property set to - the `ArrayController` instance. - - @class ArrayController - @namespace Ember - @extends Ember.ArrayProxy - @uses Ember.SortableMixin - @uses Ember.ControllerMixin - */ - - __exports__["default"] = ArrayProxy.extend(ControllerMixin, SortableMixin, { - - /** - A string containing the controller name used to wrap items. - - For example: - - ```javascript - App.MyArrayController = Ember.ArrayController.extend({ - itemController: 'myItem' // use App.MyItemController - }); - ``` - - @property itemController - @type String - @default null - */ - itemController: null, - - /** - Return the name of the controller to wrap items, or `null` if items should - be returned directly. The default implementation simply returns the - `itemController` property, but subclasses can override this method to return - different controllers for different objects. - - For example: - - ```javascript - App.MyArrayController = Ember.ArrayController.extend({ - lookupItemController: function( object ) { - if (object.get('isSpecial')) { - return "special"; // use App.SpecialController - } else { - return "regular"; // use App.RegularController - } - } - }); - ``` - - @method lookupItemController - @param {Object} object - @return {String} - */ - lookupItemController: function(object) { - return get(this, 'itemController'); - }, - - objectAtContent: function(idx) { - var length = get(this, 'length'); - var arrangedContent = get(this, 'arrangedContent'); - var object = arrangedContent && arrangedContent.objectAt(idx); - var controllerClass; - - if (idx >= 0 && idx < length) { - controllerClass = this.lookupItemController(object); - - if (controllerClass) { - return this.controllerAt(idx, object, controllerClass); - } - } - - // When `controllerClass` is falsy, we have not opted in to using item - // controllers, so return the object directly. - - // When the index is out of range, we want to return the "out of range" - // value, whatever that might be. Rather than make assumptions - // (e.g. guessing `null` or `undefined`) we defer this to `arrangedContent`. - return object; - }, - - arrangedContentDidChange: function() { - this._super(); - this._resetSubControllers(); - }, - - arrayContentDidChange: function(idx, removedCnt, addedCnt) { - var subControllers = this._subControllers; - - if (subControllers.length) { - var subControllersToRemove = subControllers.slice(idx, idx + removedCnt); - - forEach(subControllersToRemove, function(subController) { - if (subController) { - subController.destroy(); - } - }); - - replace(subControllers, idx, removedCnt, new Array(addedCnt)); - } - - // The shadow array of subcontrollers must be updated before we trigger - // observers, otherwise observers will get the wrong subcontainer when - // calling `objectAt` - this._super(idx, removedCnt, addedCnt); - }, - - init: function() { - this._super(); - this._subControllers = []; - }, - - model: computed(function () { - return Ember.A(); - }), - - /** - * Flag to mark as being "virtual". Used to keep this instance - * from participating in the parentController hierarchy. - * - * @private - * @property _isVirtual - * @type Boolean - */ - _isVirtual: false, - - controllerAt: function(idx, object, controllerClass) { - var container = get(this, 'container'); - var subControllers = this._subControllers; - var fullName, subController, subControllerFactory, parentController, options; - - if (subControllers.length > idx) { - subController = subControllers[idx]; - - if (subController) { - return subController; - } - } - - if (this._isVirtual) { - parentController = get(this, 'parentController'); - } else { - parentController = this; - } - - - fullName = 'controller:' + controllerClass; - - if (!container.has(fullName)) { - throw new EmberError('Could not resolve itemController: "' + controllerClass + '"'); - } - - subController = container.lookupFactory(fullName).create({ - target: parentController, - parentController: parentController, - model: object - }); - - - subControllers[idx] = subController; - - return subController; - }, - - _subControllers: null, - - _resetSubControllers: function() { - var controller; - var subControllers = this._subControllers; - - if (subControllers.length) { - for (var i = 0, length = subControllers.length; length > i; i++) { - controller = subControllers[i]; - - if (controller) { - controller.destroy(); - } - } - - subControllers.length = 0; - } - }, - - willDestroy: function() { - this._resetSubControllers(); - this._super(); - } - }); - }); -enifed("ember-runtime/controllers/controller", - ["ember-metal/core","ember-runtime/system/object","ember-runtime/mixins/controller","ember-runtime/inject","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - var EmberObject = __dependency2__["default"]; - var Mixin = __dependency3__["default"]; - var createInjectionHelper = __dependency4__.createInjectionHelper; - - /** - @module ember - @submodule ember-runtime - */ - - /** - @class Controller - @namespace Ember - @extends Ember.Object - @uses Ember.ControllerMixin - */ - var Controller = EmberObject.extend(Mixin); - - function controllerInjectionHelper(factory) { - Ember.assert("Defining an injected controller property on a " + - "non-controller is not allowed.", Controller.detect(factory)); - } - - - /** - Creates a property that lazily looks up another controller in the container. - Can only be used when defining another controller. - - Example: - - ```javascript - App.PostController = Ember.Controller.extend({ - posts: Ember.inject.controller() - }); - ``` - - This example will create a `posts` property on the `post` controller that - looks up the `posts` controller in the container, making it easy to - reference other controllers. This is functionally equivalent to: - - ```javascript - App.PostController = Ember.Controller.extend({ - needs: 'posts', - posts: Ember.computed.alias('controllers.posts') - }); - ``` - - @method inject.controller - @for Ember - @param {String} name (optional) name of the controller to inject, defaults - to the property's name - @return {Ember.InjectedProperty} injection descriptor instance - */ - createInjectionHelper('controller', controllerInjectionHelper); - - - __exports__["default"] = Controller; - }); -enifed("ember-runtime/controllers/object_controller", - ["ember-runtime/mixins/controller","ember-runtime/system/object_proxy","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var ControllerMixin = __dependency1__["default"]; - var ObjectProxy = __dependency2__["default"]; - - /** - @module ember - @submodule ember-runtime - */ - - /** - `Ember.ObjectController` is part of Ember's Controller layer. It is intended - to wrap a single object, proxying unhandled attempts to `get` and `set` to the underlying - model object, and to forward unhandled action attempts to its `target`. - - `Ember.ObjectController` derives this functionality from its superclass - `Ember.ObjectProxy` and the `Ember.ControllerMixin` mixin. - - @class ObjectController - @namespace Ember - @extends Ember.ObjectProxy - @uses Ember.ControllerMixin - **/ - __exports__["default"] = ObjectProxy.extend(ControllerMixin); - }); -enifed("ember-runtime/copy", - ["ember-metal/enumerable_utils","ember-metal/utils","ember-runtime/system/object","ember-runtime/mixins/copyable","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var indexOf = __dependency1__.indexOf; - var typeOf = __dependency2__.typeOf; - var EmberObject = __dependency3__["default"]; - var Copyable = __dependency4__["default"]; - - function _copy(obj, deep, seen, copies) { - var ret, loc, key; - - // primitive data types are immutable, just return them. - if (typeof obj !== 'object' || obj === null) { - return obj; - } - - // avoid cyclical loops - if (deep && (loc = indexOf(seen, obj)) >= 0) { - return copies[loc]; - } - - Ember.assert('Cannot clone an Ember.Object that does not implement Ember.Copyable', - !(obj instanceof EmberObject) || (Copyable && Copyable.detect(obj))); - - // IMPORTANT: this specific test will detect a native array only. Any other - // object will need to implement Copyable. - if (typeOf(obj) === 'array') { - ret = obj.slice(); - - if (deep) { - loc = ret.length; - - while (--loc >= 0) { - ret[loc] = _copy(ret[loc], deep, seen, copies); - } - } - } else if (Copyable && Copyable.detect(obj)) { - ret = obj.copy(deep, seen, copies); - } else if (obj instanceof Date) { - ret = new Date(obj.getTime()); - } else { - ret = {}; - - for (key in obj) { - // support Null prototype - if (!Object.prototype.hasOwnProperty.call(obj, key)) { - continue; - } - - // Prevents browsers that don't respect non-enumerability from - // copying internal Ember properties - if (key.substring(0, 2) === '__') { - continue; - } - - ret[key] = deep ? _copy(obj[key], deep, seen, copies) : obj[key]; - } - } - - if (deep) { - seen.push(obj); - copies.push(ret); - } - - return ret; - } - - /** - Creates a clone of the passed object. This function can take just about - any type of object and create a clone of it, including primitive values - (which are not actually cloned because they are immutable). - - If the passed object implements the `copy()` method, then this function - will simply call that method and return the result. Please see - `Ember.Copyable` for further details. - - @method copy - @for Ember - @param {Object} obj The object to clone - @param {Boolean} deep If true, a deep copy of the object is made - @return {Object} The cloned object - */ - __exports__["default"] = function copy(obj, deep) { - // fast paths - if ('object' !== typeof obj || obj === null) { - return obj; // can't copy primitives - } - - if (Copyable && Copyable.detect(obj)) { - return obj.copy(deep); - } - - return _copy(obj, deep, deep ? [] : null, deep ? [] : null); - } - }); -enifed("ember-runtime/core", - ["exports"], - function(__exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - /** - Compares two objects, returning true if they are logically equal. This is - a deeper comparison than a simple triple equal. For sets it will compare the - internal objects. For any other object that implements `isEqual()` it will - respect that method. - - ```javascript - Ember.isEqual('hello', 'hello'); // true - Ember.isEqual(1, 2); // false - Ember.isEqual([4, 2], [4, 2]); // false - ``` - - @method isEqual - @for Ember - @param {Object} a first object to compare - @param {Object} b second object to compare - @return {Boolean} - */ - var isEqual = function isEqual(a, b) { - if (a && typeof a.isEqual === 'function') { - return a.isEqual(b); - } - - if (a instanceof Date && b instanceof Date) { - return a.getTime() === b.getTime(); - } - - return a === b; - }; - __exports__.isEqual = isEqual; - }); -enifed("ember-runtime/ext/function", - ["ember-metal/core","ember-metal/expand_properties","ember-metal/computed","ember-metal/mixin"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - var Ember = __dependency1__["default"]; - // Ember.EXTEND_PROTOTYPES, Ember.assert - var expandProperties = __dependency2__["default"]; - var computed = __dependency3__.computed; - var observer = __dependency4__.observer; - - var a_slice = Array.prototype.slice; - var FunctionPrototype = Function.prototype; - - if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) { - - /** - The `property` extension of Javascript's Function prototype is available - when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is - `true`, which is the default. - - Computed properties allow you to treat a function like a property: - - ```javascript - MyApp.President = Ember.Object.extend({ - firstName: '', - lastName: '', - - fullName: function() { - return this.get('firstName') + ' ' + this.get('lastName'); - }.property() // Call this flag to mark the function as a property - }); - - var president = MyApp.President.create({ - firstName: 'Barack', - lastName: 'Obama' - }); - - president.get('fullName'); // 'Barack Obama' - ``` - - Treating a function like a property is useful because they can work with - bindings, just like any other property. - - Many computed properties have dependencies on other properties. For - example, in the above example, the `fullName` property depends on - `firstName` and `lastName` to determine its value. You can tell Ember - about these dependencies like this: - - ```javascript - MyApp.President = Ember.Object.extend({ - firstName: '', - lastName: '', - - fullName: function() { - return this.get('firstName') + ' ' + this.get('lastName'); - - // Tell Ember.js that this computed property depends on firstName - // and lastName - }.property('firstName', 'lastName') - }); - ``` - - Make sure you list these dependencies so Ember knows when to update - bindings that connect to a computed property. Changing a dependency - will not immediately trigger an update of the computed property, but - will instead clear the cache so that it is updated when the next `get` - is called on the property. - - See [Ember.ComputedProperty](/api/classes/Ember.ComputedProperty.html), [Ember.computed](/api/#method_computed). - - @method property - @for Function - */ - FunctionPrototype.property = function () { - var ret = computed(this); - // ComputedProperty.prototype.property expands properties; no need for us to - // do so here. - return ret.property.apply(ret, arguments); - }; - - /** - The `observes` extension of Javascript's Function prototype is available - when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is - true, which is the default. - - You can observe property changes simply by adding the `observes` - call to the end of your method declarations in classes that you write. - For example: - - ```javascript - Ember.Object.extend({ - valueObserver: function() { - // Executes whenever the "value" property changes - }.observes('value') - }); - ``` - - In the future this method may become asynchronous. If you want to ensure - synchronous behavior, use `observesImmediately`. - - See `Ember.observer`. - - @method observes - @for Function - */ - FunctionPrototype.observes = function() { - var length = arguments.length; - var args = new Array(length); - for (var x = 0; x < length; x++) { - args[x] = arguments[x]; - } - return observer.apply(this, args.concat(this)); - }; - - /** - The `observesImmediately` extension of Javascript's Function prototype is - available when `Ember.EXTEND_PROTOTYPES` or - `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default. - - You can observe property changes simply by adding the `observesImmediately` - call to the end of your method declarations in classes that you write. - For example: - - ```javascript - Ember.Object.extend({ - valueObserver: function() { - // Executes immediately after the "value" property changes - }.observesImmediately('value') - }); - ``` - - In the future, `observes` may become asynchronous. In this event, - `observesImmediately` will maintain the synchronous behavior. - - See `Ember.immediateObserver`. - - @method observesImmediately - @for Function - */ - FunctionPrototype.observesImmediately = function () { - Ember.assert('Immediate observers must observe internal properties only, ' + - 'not properties on other objects.', function checkIsInternalProperty() { - for(var i = 0, l = arguments.length; i < l; i++) { - if(arguments[i].indexOf('.') !== -1) { - return false; - } - } - return true; - }); - - // observes handles property expansion - return this.observes.apply(this, arguments); - }; - - /** - The `observesBefore` extension of Javascript's Function prototype is - available when `Ember.EXTEND_PROTOTYPES` or - `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default. - - You can get notified when a property change is about to happen by - by adding the `observesBefore` call to the end of your method - declarations in classes that you write. For example: - - ```javascript - Ember.Object.extend({ - valueObserver: function() { - // Executes whenever the "value" property is about to change - }.observesBefore('value') - }); - ``` - - See `Ember.beforeObserver`. - - @method observesBefore - @for Function - */ - FunctionPrototype.observesBefore = function () { - var watched = []; - var addWatchedProperty = function (obs) { - watched.push(obs); - }; - - for (var i = 0, l = arguments.length; i < l; ++i) { - expandProperties(arguments[i], addWatchedProperty); - } - - this.__ember_observesBefore__ = watched; - - return this; - }; - - /** - The `on` extension of Javascript's Function prototype is available - when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is - true, which is the default. - - You can listen for events simply by adding the `on` call to the end of - your method declarations in classes or mixins that you write. For example: - - ```javascript - Ember.Mixin.create({ - doSomethingWithElement: function() { - // Executes whenever the "didInsertElement" event fires - }.on('didInsertElement') - }); - ``` - - See `Ember.on`. - - @method on - @for Function - */ - FunctionPrototype.on = function () { - var events = a_slice.call(arguments); - this.__ember_listens__ = events; - - return this; - }; - } - }); -enifed("ember-runtime/ext/rsvp", - ["ember-metal/core","ember-metal/logger","ember-metal/run_loop","rsvp","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /* globals RSVP:true */ - - var Ember = __dependency1__["default"]; - var Logger = __dependency2__["default"]; - var run = __dependency3__["default"]; - - // this is technically incorrect (per @wycats) - // it should be `import * as RSVP from 'rsvp';` but - // Esprima does not support this syntax yet (and neither does - // es6-module-transpiler 0.4.0 - 0.6.2). - var RSVP = __dependency4__; - - var testModuleName = 'ember-testing/test'; - var Test; - - var asyncStart = function() { - if (Ember.Test && Ember.Test.adapter) { - Ember.Test.adapter.asyncStart(); - } - }; - - var asyncEnd = function() { - if (Ember.Test && Ember.Test.adapter) { - Ember.Test.adapter.asyncEnd(); - } - }; - - RSVP.configure('async', function(callback, promise) { - var async = !run.currentRunLoop; - - if (Ember.testing && async) { asyncStart(); } - - run.backburner.schedule('actions', function(){ - if (Ember.testing && async) { asyncEnd(); } - callback(promise); - }); - }); - - RSVP.Promise.prototype.fail = function(callback, label){ - Ember.deprecate('RSVP.Promise.fail has been renamed as RSVP.Promise.catch'); - return this['catch'](callback, label); - }; - - RSVP.onerrorDefault = function (e) { - var error; - - if (e && e.errorThrown) { - // jqXHR provides this - error = e.errorThrown; - if (typeof error === 'string') { - error = new Error(error); - } - error.__reason_with_error_thrown__ = e; - } else { - error = e; - } - - if (error && error.name !== 'TransitionAborted') { - if (Ember.testing) { - // ES6TODO: remove when possible - if (!Test && Ember.__loader.registry[testModuleName]) { - Test = requireModule(testModuleName)['default']; - } - - if (Test && Test.adapter) { - Test.adapter.exception(error); - Logger.error(error.stack); - } else { - throw error; - } - } else if (Ember.onerror) { - Ember.onerror(error); - } else { - Logger.error(error.stack); - } - } - }; - - RSVP.on('error', RSVP.onerrorDefault); - - __exports__["default"] = RSVP; - }); -enifed("ember-runtime/ext/string", - ["ember-metal/core","ember-runtime/system/string"], - function(__dependency1__, __dependency2__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - var Ember = __dependency1__["default"]; - // Ember.EXTEND_PROTOTYPES, Ember.assert, Ember.FEATURES - var fmt = __dependency2__.fmt; - var w = __dependency2__.w; - var loc = __dependency2__.loc; - var camelize = __dependency2__.camelize; - var decamelize = __dependency2__.decamelize; - var dasherize = __dependency2__.dasherize; - var underscore = __dependency2__.underscore; - var capitalize = __dependency2__.capitalize; - var classify = __dependency2__.classify; - - var StringPrototype = String.prototype; - - if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { - - /** - See [Ember.String.fmt](/api/classes/Ember.String.html#method_fmt). - - @method fmt - @for String - */ - StringPrototype.fmt = function () { - return fmt(this, arguments); - }; - - /** - See [Ember.String.w](/api/classes/Ember.String.html#method_w). - - @method w - @for String - */ - StringPrototype.w = function () { - return w(this); - }; - - /** - See [Ember.String.loc](/api/classes/Ember.String.html#method_loc). - - @method loc - @for String - */ - StringPrototype.loc = function () { - return loc(this, arguments); - }; - - /** - See [Ember.String.camelize](/api/classes/Ember.String.html#method_camelize). - - @method camelize - @for String - */ - StringPrototype.camelize = function () { - return camelize(this); - }; - - /** - See [Ember.String.decamelize](/api/classes/Ember.String.html#method_decamelize). - - @method decamelize - @for String - */ - StringPrototype.decamelize = function () { - return decamelize(this); - }; - - /** - See [Ember.String.dasherize](/api/classes/Ember.String.html#method_dasherize). - - @method dasherize - @for String - */ - StringPrototype.dasherize = function () { - return dasherize(this); - }; - - /** - See [Ember.String.underscore](/api/classes/Ember.String.html#method_underscore). - - @method underscore - @for String - */ - StringPrototype.underscore = function () { - return underscore(this); - }; - - /** - See [Ember.String.classify](/api/classes/Ember.String.html#method_classify). - - @method classify - @for String - */ - StringPrototype.classify = function () { - return classify(this); - }; - - /** - See [Ember.String.capitalize](/api/classes/Ember.String.html#method_capitalize). - - @method capitalize - @for String - */ - StringPrototype.capitalize = function () { - return capitalize(this); - }; - } - }); -enifed("ember-runtime/inject", - ["ember-metal/core","ember-metal/enumerable_utils","ember-metal/utils","ember-metal/injected_property","ember-metal/keys","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - var indexOf = __dependency2__.indexOf; - var meta = __dependency3__.meta; - var InjectedProperty = __dependency4__["default"]; - var keys = __dependency5__["default"]; - - /** - Namespace for injection helper methods. - - @class inject - @namespace Ember - */ - function inject() { - Ember.assert("Injected properties must be created through helpers, see `" + - keys(inject).join("`, `") + "`"); - } - - // Dictionary of injection validations by type, added to by `createInjectionHelper` - var typeValidators = {}; - - /** - This method allows other Ember modules to register injection helpers for a - given container type. Helpers are exported to the `inject` namespace as the - container type itself. - - @private - @method createInjectionHelper - @namespace Ember - @param {String} type The container type the helper will inject - @param {Function} validator A validation callback that is executed at mixin-time - */ - function createInjectionHelper(type, validator) { - typeValidators[type] = validator; - - inject[type] = function(name) { - return new InjectedProperty(type, name); - }; - } - - __exports__.createInjectionHelper = createInjectionHelper;/** - Validation function that runs per-type validation functions once for each - injected type encountered. - - @private - @method validatePropertyInjections - @namespace Ember - @param {Object} factory The factory object - */ - function validatePropertyInjections(factory) { - var proto = factory.proto(); - var descs = meta(proto).descs; - var types = []; - var key, desc, validator, i, l; - - for (key in descs) { - desc = descs[key]; - if (desc instanceof InjectedProperty && indexOf(types, desc.type) === -1) { - types.push(desc.type); - } - } - - if (types.length) { - for (i = 0, l = types.length; i < l; i++) { - validator = typeValidators[types[i]]; - - if (typeof validator === 'function') { - validator(factory); - } - } - } - - return true; - } - - __exports__.validatePropertyInjections = validatePropertyInjections;__exports__["default"] = inject; - }); -enifed("ember-runtime/mixins/-proxy", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/property_events","ember-metal/computed","ember-metal/properties","ember-metal/mixin","ember-runtime/system/string","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var get = __dependency2__.get; - var set = __dependency3__.set; - var meta = __dependency4__.meta; - var addObserver = __dependency5__.addObserver; - var removeObserver = __dependency5__.removeObserver; - var addBeforeObserver = __dependency5__.addBeforeObserver; - var removeBeforeObserver = __dependency5__.removeBeforeObserver; - var propertyWillChange = __dependency6__.propertyWillChange; - var propertyDidChange = __dependency6__.propertyDidChange; - var computed = __dependency7__.computed; - var defineProperty = __dependency8__.defineProperty; - var Mixin = __dependency9__.Mixin; - var observer = __dependency9__.observer; - var fmt = __dependency10__.fmt; - - function contentPropertyWillChange(content, contentKey) { - var key = contentKey.slice(8); // remove "content." - if (key in this) { return; } // if shadowed in proxy - propertyWillChange(this, key); - } - - function contentPropertyDidChange(content, contentKey) { - var key = contentKey.slice(8); // remove "content." - if (key in this) { return; } // if shadowed in proxy - propertyDidChange(this, key); - } - - /** - `Ember.ProxyMixin` forwards all properties not defined by the proxy itself - to a proxied `content` object. See Ember.ObjectProxy for more details. - - @class ProxyMixin - @namespace Ember - */ - __exports__["default"] = Mixin.create({ - /** - The object whose properties will be forwarded. - - @property content - @type Ember.Object - @default null - */ - content: null, - _contentDidChange: observer('content', function() { - Ember.assert("Can't set Proxy's content to itself", get(this, 'content') !== this); - }), - - isTruthy: computed.bool('content'), - - _debugContainerKey: null, - - willWatchProperty: function (key) { - var contentKey = 'content.' + key; - addBeforeObserver(this, contentKey, null, contentPropertyWillChange); - addObserver(this, contentKey, null, contentPropertyDidChange); - }, - - didUnwatchProperty: function (key) { - var contentKey = 'content.' + key; - removeBeforeObserver(this, contentKey, null, contentPropertyWillChange); - removeObserver(this, contentKey, null, contentPropertyDidChange); - }, - - unknownProperty: function (key) { - var content = get(this, 'content'); - if (content) { - return get(content, key); - } - }, - - setUnknownProperty: function (key, value) { - var m = meta(this); - if (m.proto === this) { - // if marked as prototype then just defineProperty - // rather than delegate - defineProperty(this, key, null, value); - return value; - } - - var content = get(this, 'content'); - Ember.assert(fmt("Cannot delegate set('%@', %@) to the 'content' property of" + - " object proxy %@: its 'content' is undefined.", [key, value, this]), content); - return set(content, key, value); - } - - }); - }); -enifed("ember-runtime/mixins/action_handler", - ["ember-metal/merge","ember-metal/mixin","ember-metal/property_get","ember-metal/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - var merge = __dependency1__["default"]; - var Mixin = __dependency2__.Mixin; - var get = __dependency3__.get; - var typeOf = __dependency4__.typeOf; - - /** - The `Ember.ActionHandler` mixin implements support for moving an `actions` - property to an `_actions` property at extend time, and adding `_actions` - to the object's mergedProperties list. - - `Ember.ActionHandler` is available on some familiar classes including - `Ember.Route`, `Ember.View`, `Ember.Component`, and controllers such as - `Ember.Controller` and `Ember.ObjectController`. - (Internally the mixin is used by `Ember.CoreView`, `Ember.ControllerMixin`, - and `Ember.Route` and available to the above classes through - inheritance.) - - @class ActionHandler - @namespace Ember - */ - var ActionHandler = Mixin.create({ - mergedProperties: ['_actions'], - - /** - The collection of functions, keyed by name, available on this - `ActionHandler` as action targets. - - These functions will be invoked when a matching `{{action}}` is triggered - from within a template and the application's current route is this route. - - Actions can also be invoked from other parts of your application - via `ActionHandler#send`. - - The `actions` hash will inherit action handlers from - the `actions` hash defined on extended parent classes - or mixins rather than just replace the entire hash, e.g.: - - ```js - App.CanDisplayBanner = Ember.Mixin.create({ - actions: { - displayBanner: function(msg) { - // ... - } - } - }); - - App.WelcomeRoute = Ember.Route.extend(App.CanDisplayBanner, { - actions: { - playMusic: function() { - // ... - } - } - }); - - // `WelcomeRoute`, when active, will be able to respond - // to both actions, since the actions hash is merged rather - // then replaced when extending mixins / parent classes. - this.send('displayBanner'); - this.send('playMusic'); - ``` - - Within a Controller, Route, View or Component's action handler, - the value of the `this` context is the Controller, Route, View or - Component object: - - ```js - App.SongRoute = Ember.Route.extend({ - actions: { - myAction: function() { - this.controllerFor("song"); - this.transitionTo("other.route"); - ... - } - } - }); - ``` - - It is also possible to call `this._super()` from within an - action handler if it overrides a handler defined on a parent - class or mixin: - - Take for example the following routes: - - ```js - App.DebugRoute = Ember.Mixin.create({ - actions: { - debugRouteInformation: function() { - console.debug("trololo"); - } - } - }); - - App.AnnoyingDebugRoute = Ember.Route.extend(App.DebugRoute, { - actions: { - debugRouteInformation: function() { - // also call the debugRouteInformation of mixed in App.DebugRoute - this._super(); - - // show additional annoyance - window.alert(...); - } - } - }); - ``` - - ## Bubbling - - By default, an action will stop bubbling once a handler defined - on the `actions` hash handles it. To continue bubbling the action, - you must return `true` from the handler: - - ```js - App.Router.map(function() { - this.resource("album", function() { - this.route("song"); - }); - }); - - App.AlbumRoute = Ember.Route.extend({ - actions: { - startPlaying: function() { - } - } - }); - - App.AlbumSongRoute = Ember.Route.extend({ - actions: { - startPlaying: function() { - // ... - - if (actionShouldAlsoBeTriggeredOnParentRoute) { - return true; - } - } - } - }); - ``` - - @property actions - @type Hash - @default null - */ - - /** - Moves `actions` to `_actions` at extend time. Note that this currently - modifies the mixin themselves, which is technically dubious but - is practically of little consequence. This may change in the future. - - @private - @method willMergeMixin - */ - willMergeMixin: function(props) { - var hashName; - - if (!props._actions) { - Ember.assert("'actions' should not be a function", typeof(props.actions) !== 'function'); - - if (typeOf(props.actions) === 'object') { - hashName = 'actions'; - } else if (typeOf(props.events) === 'object') { - Ember.deprecate('Action handlers contained in an `events` object are deprecated in favor' + - ' of putting them in an `actions` object', false); - hashName = 'events'; - } - - if (hashName) { - props._actions = merge(props._actions || {}, props[hashName]); - } - - delete props[hashName]; - } - }, - - /** - Triggers a named action on the `ActionHandler`. Any parameters - supplied after the `actionName` string will be passed as arguments - to the action target function. - - If the `ActionHandler` has its `target` property set, actions may - bubble to the `target`. Bubbling happens when an `actionName` can - not be found in the `ActionHandler`'s `actions` hash or if the - action target function returns `true`. - - Example - - ```js - App.WelcomeRoute = Ember.Route.extend({ - actions: { - playTheme: function() { - this.send('playMusic', 'theme.mp3'); - }, - playMusic: function(track) { - // ... - } - } - }); - ``` - - @method send - @param {String} actionName The action to trigger - @param {*} context a context to send with the action - */ - send: function(actionName) { - var args = [].slice.call(arguments, 1); - var target; - - if (this._actions && this._actions[actionName]) { - if (this._actions[actionName].apply(this, args) === true) { - // handler returned true, so this action will bubble - } else { - return; - } - } - - if (target = get(this, 'target')) { - Ember.assert("The `target` for " + this + " (" + target + - ") does not have a `send` method", typeof target.send === 'function'); - target.send.apply(target, arguments); - } - } - }); - - __exports__["default"] = ActionHandler; - }); -enifed("ember-runtime/mixins/array", - ["ember-metal/core","ember-metal/property_get","ember-metal/computed","ember-metal/is_none","ember-runtime/mixins/enumerable","ember-metal/enumerable_utils","ember-metal/mixin","ember-metal/property_events","ember-metal/events","ember-metal/watching","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - // .......................................................... - // HELPERS - // - var Ember = __dependency1__["default"]; - // ES6TODO: Ember.A - - var get = __dependency2__.get; - var computed = __dependency3__.computed; - var cacheFor = __dependency3__.cacheFor; - var isNone = __dependency4__["default"]; - var Enumerable = __dependency5__["default"]; - var map = __dependency6__.map; - var Mixin = __dependency7__.Mixin; - var required = __dependency7__.required; - var propertyWillChange = __dependency8__.propertyWillChange; - var propertyDidChange = __dependency8__.propertyDidChange; - var addListener = __dependency9__.addListener; - var removeListener = __dependency9__.removeListener; - var sendEvent = __dependency9__.sendEvent; - var hasListeners = __dependency9__.hasListeners; - var isWatching = __dependency10__.isWatching; - - function arrayObserversHelper(obj, target, opts, operation, notify) { - var willChange = (opts && opts.willChange) || 'arrayWillChange'; - var didChange = (opts && opts.didChange) || 'arrayDidChange'; - var hasObservers = get(obj, 'hasArrayObservers'); - - if (hasObservers === notify) { - propertyWillChange(obj, 'hasArrayObservers'); - } - - operation(obj, '@array:before', target, willChange); - operation(obj, '@array:change', target, didChange); - - if (hasObservers === notify) { - propertyDidChange(obj, 'hasArrayObservers'); - } - - return obj; - } - - // .......................................................... - // ARRAY - // - /** - This mixin implements Observer-friendly Array-like behavior. It is not a - concrete implementation, but it can be used up by other classes that want - to appear like arrays. - - For example, ArrayProxy and ArrayController are both concrete classes that can - be instantiated to implement array-like behavior. Both of these classes use - the Array Mixin by way of the MutableArray mixin, which allows observable - changes to be made to the underlying array. - - Unlike `Ember.Enumerable,` this mixin defines methods specifically for - collections that provide index-ordered access to their contents. When you - are designing code that needs to accept any kind of Array-like object, you - should use these methods instead of Array primitives because these will - properly notify observers of changes to the array. - - Although these methods are efficient, they do add a layer of indirection to - your application so it is a good idea to use them only when you need the - flexibility of using both true JavaScript arrays and "virtual" arrays such - as controllers and collections. - - You can use the methods defined in this module to access and modify array - contents in a KVO-friendly way. You can also be notified whenever the - membership of an array changes by using `.observes('myArray.[]')`. - - To support `Ember.Array` in your own class, you must override two - primitives to use it: `replace()` and `objectAt()`. - - Note that the Ember.Array mixin also incorporates the `Ember.Enumerable` - mixin. All `Ember.Array`-like objects are also enumerable. - - @class Array - @namespace Ember - @uses Ember.Enumerable - @since Ember 0.9.0 - */ - __exports__["default"] = Mixin.create(Enumerable, { - - /** - Your array must support the `length` property. Your replace methods should - set this property whenever it changes. - - @property {Number} length - */ - length: required(), - - /** - Returns the object at the given `index`. If the given `index` is negative - or is greater or equal than the array length, returns `undefined`. - - This is one of the primitives you must implement to support `Ember.Array`. - If your object supports retrieving the value of an array item using `get()` - (i.e. `myArray.get(0)`), then you do not need to implement this method - yourself. - - ```javascript - var arr = ['a', 'b', 'c', 'd']; - - arr.objectAt(0); // 'a' - arr.objectAt(3); // 'd' - arr.objectAt(-1); // undefined - arr.objectAt(4); // undefined - arr.objectAt(5); // undefined - ``` - - @method objectAt - @param {Number} idx The index of the item to return. - @return {*} item at index or undefined - */ - objectAt: function(idx) { - if (idx < 0 || idx >= get(this, 'length')) { - return undefined; - } - - return get(this, idx); - }, - - /** - This returns the objects at the specified indexes, using `objectAt`. - - ```javascript - var arr = ['a', 'b', 'c', 'd']; - - arr.objectsAt([0, 1, 2]); // ['a', 'b', 'c'] - arr.objectsAt([2, 3, 4]); // ['c', 'd', undefined] - ``` - - @method objectsAt - @param {Array} indexes An array of indexes of items to return. - @return {Array} - */ - objectsAt: function(indexes) { - var self = this; - - return map(indexes, function(idx) { - return self.objectAt(idx); - }); - }, - - // overrides Ember.Enumerable version - nextObject: function(idx) { - return this.objectAt(idx); - }, - - /** - This is the handler for the special array content property. If you get - this property, it will return this. If you set this property to a new - array, it will replace the current content. - - This property overrides the default property defined in `Ember.Enumerable`. - - @property [] - @return this - */ - '[]': computed(function(key, value) { - if (value !== undefined) { - this.replace(0, get(this, 'length'), value); - } - - return this; - }), - - firstObject: computed(function() { - return this.objectAt(0); - }), - - lastObject: computed(function() { - return this.objectAt(get(this, 'length') - 1); - }), - - // optimized version from Enumerable - contains: function(obj) { - return this.indexOf(obj) >= 0; - }, - - // Add any extra methods to Ember.Array that are native to the built-in Array. - /** - Returns a new array that is a slice of the receiver. This implementation - uses the observable array methods to retrieve the objects for the new - slice. - - ```javascript - var arr = ['red', 'green', 'blue']; - - arr.slice(0); // ['red', 'green', 'blue'] - arr.slice(0, 2); // ['red', 'green'] - arr.slice(1, 100); // ['green', 'blue'] - ``` - - @method slice - @param {Integer} beginIndex (Optional) index to begin slicing from. - @param {Integer} endIndex (Optional) index to end the slice at (but not included). - @return {Array} New array with specified slice - */ - slice: function(beginIndex, endIndex) { - var ret = Ember.A(); - var length = get(this, 'length'); - - if (isNone(beginIndex)) { - beginIndex = 0; - } - - if (isNone(endIndex) || (endIndex > length)) { - endIndex = length; - } - - if (beginIndex < 0) { - beginIndex = length + beginIndex; - } - - if (endIndex < 0) { - endIndex = length + endIndex; - } - - while (beginIndex < endIndex) { - ret[ret.length] = this.objectAt(beginIndex++); - } - - return ret; - }, - - /** - Returns the index of the given object's first occurrence. - If no `startAt` argument is given, the starting location to - search is 0. If it's negative, will count backward from - the end of the array. Returns -1 if no match is found. - - ```javascript - var arr = ['a', 'b', 'c', 'd', 'a']; - - arr.indexOf('a'); // 0 - arr.indexOf('z'); // -1 - arr.indexOf('a', 2); // 4 - arr.indexOf('a', -1); // 4 - arr.indexOf('b', 3); // -1 - arr.indexOf('a', 100); // -1 - ``` - - @method indexOf - @param {Object} object the item to search for - @param {Number} startAt optional starting location to search, default 0 - @return {Number} index or -1 if not found - */ - indexOf: function(object, startAt) { - var len = get(this, 'length'); - var idx; - - if (startAt === undefined) { - startAt = 0; - } - - if (startAt < 0) { - startAt += len; - } - - for (idx = startAt; idx < len; idx++) { - if (this.objectAt(idx) === object) { - return idx; - } - } - - return -1; - }, - - /** - Returns the index of the given object's last occurrence. - If no `startAt` argument is given, the search starts from - the last position. If it's negative, will count backward - from the end of the array. Returns -1 if no match is found. - - ```javascript - var arr = ['a', 'b', 'c', 'd', 'a']; - - arr.lastIndexOf('a'); // 4 - arr.lastIndexOf('z'); // -1 - arr.lastIndexOf('a', 2); // 0 - arr.lastIndexOf('a', -1); // 4 - arr.lastIndexOf('b', 3); // 1 - arr.lastIndexOf('a', 100); // 4 - ``` - - @method lastIndexOf - @param {Object} object the item to search for - @param {Number} startAt optional starting location to search, default 0 - @return {Number} index or -1 if not found - */ - lastIndexOf: function(object, startAt) { - var len = get(this, 'length'); - var idx; - - if (startAt === undefined || startAt >= len) { - startAt = len-1; - } - - if (startAt < 0) { - startAt += len; - } - - for (idx = startAt; idx >= 0; idx--) { - if (this.objectAt(idx) === object) { - return idx; - } - } - - return -1; - }, - - // .......................................................... - // ARRAY OBSERVERS - // - - /** - Adds an array observer to the receiving array. The array observer object - normally must implement two methods: - - * `arrayWillChange(observedObj, start, removeCount, addCount)` - This method will be - called just before the array is modified. - * `arrayDidChange(observedObj, start, removeCount, addCount)` - This method will be - called just after the array is modified. - - Both callbacks will be passed the observed object, starting index of the - change as well a a count of the items to be removed and added. You can use - these callbacks to optionally inspect the array during the change, clear - caches, or do any other bookkeeping necessary. - - In addition to passing a target, you can also include an options hash - which you can use to override the method names that will be invoked on the - target. - - @method addArrayObserver - @param {Object} target The observer object. - @param {Hash} opts Optional hash of configuration options including - `willChange` and `didChange` option. - @return {Ember.Array} receiver - */ - - addArrayObserver: function(target, opts) { - return arrayObserversHelper(this, target, opts, addListener, false); - }, - - /** - Removes an array observer from the object if the observer is current - registered. Calling this method multiple times with the same object will - have no effect. - - @method removeArrayObserver - @param {Object} target The object observing the array. - @param {Hash} opts Optional hash of configuration options including - `willChange` and `didChange` option. - @return {Ember.Array} receiver - */ - removeArrayObserver: function(target, opts) { - return arrayObserversHelper(this, target, opts, removeListener, true); - }, - - /** - Becomes true whenever the array currently has observers watching changes - on the array. - - @property {Boolean} hasArrayObservers - */ - hasArrayObservers: computed(function() { - return hasListeners(this, '@array:change') || hasListeners(this, '@array:before'); - }), - - /** - If you are implementing an object that supports `Ember.Array`, call this - method just before the array content changes to notify any observers and - invalidate any related properties. Pass the starting index of the change - as well as a delta of the amounts to change. - - @method arrayContentWillChange - @param {Number} startIdx The starting index in the array that will change. - @param {Number} removeAmt The number of items that will be removed. If you - pass `null` assumes 0 - @param {Number} addAmt The number of items that will be added. If you - pass `null` assumes 0. - @return {Ember.Array} receiver - */ - arrayContentWillChange: function(startIdx, removeAmt, addAmt) { - var removing, lim; - - // if no args are passed assume everything changes - if (startIdx === undefined) { - startIdx = 0; - removeAmt = addAmt = -1; - } else { - if (removeAmt === undefined) { - removeAmt = -1; - } - - if (addAmt === undefined) { - addAmt = -1; - } - } - - // Make sure the @each proxy is set up if anyone is observing @each - if (isWatching(this, '@each')) { - get(this, '@each'); - } - - sendEvent(this, '@array:before', [this, startIdx, removeAmt, addAmt]); - - if (startIdx >= 0 && removeAmt >= 0 && get(this, 'hasEnumerableObservers')) { - removing = []; - lim = startIdx + removeAmt; - - for (var idx = startIdx; idx < lim; idx++) { - removing.push(this.objectAt(idx)); - } - } else { - removing = removeAmt; - } - - this.enumerableContentWillChange(removing, addAmt); - - return this; - }, - - /** - If you are implementing an object that supports `Ember.Array`, call this - method just after the array content changes to notify any observers and - invalidate any related properties. Pass the starting index of the change - as well as a delta of the amounts to change. - - @method arrayContentDidChange - @param {Number} startIdx The starting index in the array that did change. - @param {Number} removeAmt The number of items that were removed. If you - pass `null` assumes 0 - @param {Number} addAmt The number of items that were added. If you - pass `null` assumes 0. - @return {Ember.Array} receiver - */ - arrayContentDidChange: function(startIdx, removeAmt, addAmt) { - var adding, lim; - - // if no args are passed assume everything changes - if (startIdx === undefined) { - startIdx = 0; - removeAmt = addAmt = -1; - } else { - if (removeAmt === undefined) { - removeAmt = -1; - } - - if (addAmt === undefined) { - addAmt = -1; - } - } - - if (startIdx >= 0 && addAmt >= 0 && get(this, 'hasEnumerableObservers')) { - adding = []; - lim = startIdx + addAmt; - - for (var idx = startIdx; idx < lim; idx++) { - adding.push(this.objectAt(idx)); - } - } else { - adding = addAmt; - } - - this.enumerableContentDidChange(removeAmt, adding); - sendEvent(this, '@array:change', [this, startIdx, removeAmt, addAmt]); - - var length = get(this, 'length'); - var cachedFirst = cacheFor(this, 'firstObject'); - var cachedLast = cacheFor(this, 'lastObject'); - - if (this.objectAt(0) !== cachedFirst) { - propertyWillChange(this, 'firstObject'); - propertyDidChange(this, 'firstObject'); - } - - if (this.objectAt(length-1) !== cachedLast) { - propertyWillChange(this, 'lastObject'); - propertyDidChange(this, 'lastObject'); - } - - return this; - }, - - // .......................................................... - // ENUMERATED PROPERTIES - // - - /** - Returns a special object that can be used to observe individual properties - on the array. Just get an equivalent property on this object and it will - return an enumerable that maps automatically to the named key on the - member objects. - - If you merely want to watch for any items being added or removed to the array, - use the `[]` property instead of `@each`. - - @property @each - */ - '@each': computed(function() { - if (!this.__each) { - // ES6TODO: GRRRRR - var EachProxy = requireModule('ember-runtime/system/each_proxy')['EachProxy']; - - this.__each = new EachProxy(this); - } - - return this.__each; - }) - }); - }); -enifed("ember-runtime/mixins/comparable", - ["ember-metal/mixin","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Mixin = __dependency1__.Mixin; - var required = __dependency1__.required; - - /** - @module ember - @submodule ember-runtime - */ - - /** - Implements some standard methods for comparing objects. Add this mixin to - any class you create that can compare its instances. - - You should implement the `compare()` method. - - @class Comparable - @namespace Ember - @since Ember 0.9 - */ - __exports__["default"] = Mixin.create({ - - /** - Override to return the result of the comparison of the two parameters. The - compare method should return: - - - `-1` if `a < b` - - `0` if `a == b` - - `1` if `a > b` - - Default implementation raises an exception. - - @method compare - @param a {Object} the first object to compare - @param b {Object} the second object to compare - @return {Integer} the result of the comparison - */ - compare: required(Function) - }); - }); -enifed("ember-runtime/mixins/controller", - ["ember-metal/mixin","ember-metal/computed","ember-runtime/mixins/action_handler","ember-runtime/mixins/controller_content_model_alias_deprecation","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var Mixin = __dependency1__.Mixin; - var computed = __dependency2__.computed; - var ActionHandler = __dependency3__["default"]; - var ControllerContentModelAliasDeprecation = __dependency4__["default"]; - - /** - `Ember.ControllerMixin` provides a standard interface for all classes that - compose Ember's controller layer: `Ember.Controller`, - `Ember.ArrayController`, and `Ember.ObjectController`. - - @class ControllerMixin - @namespace Ember - @uses Ember.ActionHandler - */ - __exports__["default"] = Mixin.create(ActionHandler, ControllerContentModelAliasDeprecation, { - /* ducktype as a controller */ - isController: true, - - /** - The object to which actions from the view should be sent. - - For example, when a Handlebars template uses the `{{action}}` helper, - it will attempt to send the action to the view's controller's `target`. - - By default, the value of the target property is set to the router, and - is injected when a controller is instantiated. This injection is defined - in Ember.Application#buildContainer, and is applied as part of the - applications initialization process. It can also be set after a controller - has been instantiated, for instance when using the render helper in a - template, or when a controller is used as an `itemController`. In most - cases the `target` property will automatically be set to the logical - consumer of actions for the controller. - - @property target - @default null - */ - target: null, - - container: null, - - parentController: null, - - store: null, - - /** - The controller's current model. When retrieving or modifying a controller's - model, this property should be used instead of the `content` property. - - @property model - @public - */ - model: null, - - /** - @private - */ - content: computed.alias('model') - - }); - }); -enifed("ember-runtime/mixins/controller_content_model_alias_deprecation", - ["ember-metal/core","ember-metal/mixin","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.deprecate - var Mixin = __dependency2__.Mixin; - - /** - The ControllerContentModelAliasDeprecation mixin is used to provide a useful - deprecation warning when specifying `content` directly on a `Ember.Controller` - (without also specifying `model`). - - Ember versions prior to 1.7 used `model` as an alias of `content`, but due to - much confusion this alias was reversed (so `content` is now an alias of `model). - - This change reduces many caveats with model/content, and also sets a - simple ground rule: Never set a controllers content, rather always set - its model and ember will do the right thing. - - - `Ember.ControllerContentModelAliasDeprecation` is used internally by Ember in - `Ember.Controller`. - - @class ControllerContentModelAliasDeprecation - @namespace Ember - @private - @since 1.7.0 - */ - __exports__["default"] = Mixin.create({ - /** - @private - - Moves `content` to `model` at extend time if a `model` is not also specified. - - Note that this currently modifies the mixin themselves, which is technically - dubious but is practically of little consequence. This may change in the - future. - - @method willMergeMixin - @since 1.4.0 - */ - willMergeMixin: function(props) { - // Calling super is only OK here since we KNOW that - // there is another Mixin loaded first. - this._super.apply(this, arguments); - - var modelSpecified = !!props.model; - - if (props.content && !modelSpecified) { - props.model = props.content; - delete props['content']; - - Ember.deprecate('Do not specify `content` on a Controller, use `model` instead.', false); - } - } - }); - }); -enifed("ember-runtime/mixins/copyable", - ["ember-metal/property_get","ember-metal/mixin","ember-runtime/mixins/freezable","ember-runtime/system/string","ember-metal/error","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - - var get = __dependency1__.get; - var required = __dependency2__.required; - var Freezable = __dependency3__.Freezable; - var Mixin = __dependency2__.Mixin; - var fmt = __dependency4__.fmt; - var EmberError = __dependency5__["default"]; - - - /** - Implements some standard methods for copying an object. Add this mixin to - any object you create that can create a copy of itself. This mixin is - added automatically to the built-in array. - - You should generally implement the `copy()` method to return a copy of the - receiver. - - Note that `frozenCopy()` will only work if you also implement - `Ember.Freezable`. - - @class Copyable - @namespace Ember - @since Ember 0.9 - */ - __exports__["default"] = Mixin.create({ - /** - Override to return a copy of the receiver. Default implementation raises - an exception. - - @method copy - @param {Boolean} deep if `true`, a deep copy of the object should be made - @return {Object} copy of receiver - */ - copy: required(Function), - - /** - If the object implements `Ember.Freezable`, then this will return a new - copy if the object is not frozen and the receiver if the object is frozen. - - Raises an exception if you try to call this method on a object that does - not support freezing. - - You should use this method whenever you want a copy of a freezable object - since a freezable object can simply return itself without actually - consuming more memory. - - @method frozenCopy - @return {Object} copy of receiver or receiver - */ - frozenCopy: function() { - if (Freezable && Freezable.detect(this)) { - return get(this, 'isFrozen') ? this : this.copy().freeze(); - } else { - throw new EmberError(fmt("%@ does not support freezing", [this])); - } - } - }); - }); -enifed("ember-runtime/mixins/deferred", - ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","ember-metal/computed","ember-runtime/ext/rsvp","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.FEATURES, Ember.Test - var get = __dependency2__.get; - var Mixin = __dependency3__.Mixin; - var computed = __dependency4__.computed; - var RSVP = __dependency5__["default"]; - - /** - @module ember - @submodule ember-runtime - */ - - - /** - @class Deferred - @namespace Ember - */ - __exports__["default"] = Mixin.create({ - /** - Add handlers to be called when the Deferred object is resolved or rejected. - - @method then - @param {Function} resolve a callback function to be called when done - @param {Function} reject a callback function to be called when failed - */ - then: function(resolve, reject, label) { - var deferred, promise, entity; - - entity = this; - deferred = get(this, '_deferred'); - promise = deferred.promise; - - function fulfillmentHandler(fulfillment) { - if (fulfillment === promise) { - return resolve(entity); - } else { - return resolve(fulfillment); - } - } - - return promise.then(resolve && fulfillmentHandler, reject, label); - }, - - /** - Resolve a Deferred object and call any `doneCallbacks` with the given args. - - @method resolve - */ - resolve: function(value) { - var deferred, promise; - - deferred = get(this, '_deferred'); - promise = deferred.promise; - - if (value === this) { - deferred.resolve(promise); - } else { - deferred.resolve(value); - } - }, - - /** - Reject a Deferred object and call any `failCallbacks` with the given args. - - @method reject - */ - reject: function(value) { - get(this, '_deferred').reject(value); - }, - - _deferred: computed(function() { - Ember.deprecate('Usage of Ember.DeferredMixin or Ember.Deferred is deprecated.', this._suppressDeferredDeprecation, { url: 'http://emberjs.com/guides/deprecations/#toc_deprecate-ember-deferredmixin-and-ember-deferred' }); - - return RSVP.defer('Ember: DeferredMixin - ' + this); - }) - }); - }); -enifed("ember-runtime/mixins/enumerable", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/property_events","ember-metal/events","ember-runtime/compare","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - // .......................................................... - // HELPERS - // - - var Ember = __dependency1__["default"]; - var get = __dependency2__.get; - var set = __dependency3__.set; - var apply = __dependency4__.apply; - var Mixin = __dependency5__.Mixin; - var required = __dependency5__.required; - var aliasMethod = __dependency5__.aliasMethod; - var indexOf = __dependency6__.indexOf; - var computed = __dependency7__.computed; - var propertyWillChange = __dependency8__.propertyWillChange; - var propertyDidChange = __dependency8__.propertyDidChange; - var addListener = __dependency9__.addListener; - var removeListener = __dependency9__.removeListener; - var sendEvent = __dependency9__.sendEvent; - var hasListeners = __dependency9__.hasListeners; - var compare = __dependency10__["default"]; - - var a_slice = Array.prototype.slice; - - var contexts = []; - - function popCtx() { - return contexts.length === 0 ? {} : contexts.pop(); - } - - function pushCtx(ctx) { - contexts.push(ctx); - return null; - } - - function iter(key, value) { - var valueProvided = arguments.length === 2; - - function i(item) { - var cur = get(item, key); - return valueProvided ? value === cur : !!cur; - } - - return i; - } - - /** - This mixin defines the common interface implemented by enumerable objects - in Ember. Most of these methods follow the standard Array iteration - API defined up to JavaScript 1.8 (excluding language-specific features that - cannot be emulated in older versions of JavaScript). - - This mixin is applied automatically to the Array class on page load, so you - can use any of these methods on simple arrays. If Array already implements - one of these methods, the mixin will not override them. - - ## Writing Your Own Enumerable - - To make your own custom class enumerable, you need two items: - - 1. You must have a length property. This property should change whenever - the number of items in your enumerable object changes. If you use this - with an `Ember.Object` subclass, you should be sure to change the length - property using `set().` - - 2. You must implement `nextObject().` See documentation. - - Once you have these two methods implemented, apply the `Ember.Enumerable` mixin - to your class and you will be able to enumerate the contents of your object - like any other collection. - - ## Using Ember Enumeration with Other Libraries - - Many other libraries provide some kind of iterator or enumeration like - facility. This is often where the most common API conflicts occur. - Ember's API is designed to be as friendly as possible with other - libraries by implementing only methods that mostly correspond to the - JavaScript 1.8 API. - - @class Enumerable - @namespace Ember - @since Ember 0.9 - */ - __exports__["default"] = Mixin.create({ - - /** - Implement this method to make your class enumerable. - - This method will be call repeatedly during enumeration. The index value - will always begin with 0 and increment monotonically. You don't have to - rely on the index value to determine what object to return, but you should - always check the value and start from the beginning when you see the - requested index is 0. - - The `previousObject` is the object that was returned from the last call - to `nextObject` for the current iteration. This is a useful way to - manage iteration if you are tracing a linked list, for example. - - Finally the context parameter will always contain a hash you can use as - a "scratchpad" to maintain any other state you need in order to iterate - properly. The context object is reused and is not reset between - iterations so make sure you setup the context with a fresh state whenever - the index parameter is 0. - - Generally iterators will continue to call `nextObject` until the index - reaches the your current length-1. If you run out of data before this - time for some reason, you should simply return undefined. - - The default implementation of this method simply looks up the index. - This works great on any Array-like objects. - - @method nextObject - @param {Number} index the current index of the iteration - @param {Object} previousObject the value returned by the last call to - `nextObject`. - @param {Object} context a context object you can use to maintain state. - @return {Object} the next object in the iteration or undefined - */ - nextObject: required(Function), - - /** - Helper method returns the first object from a collection. This is usually - used by bindings and other parts of the framework to extract a single - object if the enumerable contains only one item. - - If you override this method, you should implement it so that it will - always return the same value each time it is called. If your enumerable - contains only one object, this method should always return that object. - If your enumerable is empty, this method should return `undefined`. - - ```javascript - var arr = ['a', 'b', 'c']; - arr.get('firstObject'); // 'a' - - var arr = []; - arr.get('firstObject'); // undefined - ``` - - @property firstObject - @return {Object} the object or undefined - */ - firstObject: computed('[]', function() { - if (get(this, 'length') === 0) { - return undefined; - } - - // handle generic enumerables - var context = popCtx(); - var ret = this.nextObject(0, null, context); - - pushCtx(context); - - return ret; - }), - - /** - Helper method returns the last object from a collection. If your enumerable - contains only one object, this method should always return that object. - If your enumerable is empty, this method should return `undefined`. - - ```javascript - var arr = ['a', 'b', 'c']; - arr.get('lastObject'); // 'c' - - var arr = []; - arr.get('lastObject'); // undefined - ``` - - @property lastObject - @return {Object} the last object or undefined - */ - lastObject: computed('[]', function() { - var len = get(this, 'length'); - - if (len === 0) { - return undefined; - } - - var context = popCtx(); - var idx = 0; - var last = null; - var cur; - - do { - last = cur; - cur = this.nextObject(idx++, last, context); - } while (cur !== undefined); - - pushCtx(context); - - return last; - }), - - /** - Returns `true` if the passed object can be found in the receiver. The - default version will iterate through the enumerable until the object - is found. You may want to override this with a more efficient version. - - ```javascript - var arr = ['a', 'b', 'c']; - - arr.contains('a'); // true - arr.contains('z'); // false - ``` - - @method contains - @param {Object} obj The object to search for. - @return {Boolean} `true` if object is found in enumerable. - */ - contains: function(obj) { - var found = this.find(function(item) { - return item === obj; - }); - - return found !== undefined; - }, - - /** - Iterates through the enumerable, calling the passed function on each - item. This method corresponds to the `forEach()` method defined in - JavaScript 1.6. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(item, index, enumerable); - ``` - - - `item` is the current item in the iteration. - - `index` is the current index in the iteration. - - `enumerable` is the enumerable object itself. - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. This is a good way - to give your iterator function access to the current object. - - @method forEach - @param {Function} callback The callback to execute - @param {Object} [target] The target object to use - @return {Object} receiver - */ - forEach: function(callback, target) { - if (typeof callback !== 'function') { - throw new TypeError(); - } - - var context = popCtx(); - var len = get(this, 'length'); - var last = null; - - if (target === undefined) { - target = null; - } - - for(var idx = 0; idx < len; idx++) { - var next = this.nextObject(idx, last, context) ; - callback.call(target, next, idx, this); - last = next ; - } - - last = null ; - context = pushCtx(context); - - return this ; - }, - - /** - Alias for `mapBy` - - @method getEach - @param {String} key name of the property - @return {Array} The mapped array. - */ - getEach: function(key) { - return this.mapBy(key); - }, - - /** - Sets the value on the named property for each member. This is more - efficient than using other methods defined on this helper. If the object - implements Ember.Observable, the value will be changed to `set(),` otherwise - it will be set directly. `null` objects are skipped. - - @method setEach - @param {String} key The key to set - @param {Object} value The object to set - @return {Object} receiver - */ - setEach: function(key, value) { - return this.forEach(function(item) { - set(item, key, value); - }); - }, - - /** - Maps all of the items in the enumeration to another value, returning - a new array. This method corresponds to `map()` defined in JavaScript 1.6. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(item, index, enumerable); - ``` - - - `item` is the current item in the iteration. - - `index` is the current index in the iteration. - - `enumerable` is the enumerable object itself. - - It should return the mapped value. - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. This is a good way - to give your iterator function access to the current object. - - @method map - @param {Function} callback The callback to execute - @param {Object} [target] The target object to use - @return {Array} The mapped array. - */ - map: function(callback, target) { - var ret = Ember.A(); - - this.forEach(function(x, idx, i) { - ret[idx] = callback.call(target, x, idx,i); - }); - - return ret ; - }, - - /** - Similar to map, this specialized function returns the value of the named - property on all items in the enumeration. - - @method mapBy - @param {String} key name of the property - @return {Array} The mapped array. - */ - mapBy: function(key) { - return this.map(function(next) { - return get(next, key); - }); - }, - - /** - Similar to map, this specialized function returns the value of the named - property on all items in the enumeration. - - @method mapProperty - @param {String} key name of the property - @return {Array} The mapped array. - @deprecated Use `mapBy` instead - */ - - mapProperty: aliasMethod('mapBy'), - - /** - Returns an array with all of the items in the enumeration that the passed - function returns true for. This method corresponds to `filter()` defined in - JavaScript 1.6. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(item, index, enumerable); - ``` - - - `item` is the current item in the iteration. - - `index` is the current index in the iteration. - - `enumerable` is the enumerable object itself. - - It should return `true` to include the item in the results, `false` - otherwise. - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. This is a good way - to give your iterator function access to the current object. - - @method filter - @param {Function} callback The callback to execute - @param {Object} [target] The target object to use - @return {Array} A filtered array. - */ - filter: function(callback, target) { - var ret = Ember.A(); - - this.forEach(function(x, idx, i) { - if (callback.call(target, x, idx, i)) { - ret.push(x); - } - }); - - return ret ; - }, - - /** - Returns an array with all of the items in the enumeration where the passed - function returns false for. This method is the inverse of filter(). - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(item, index, enumerable); - ``` - - - *item* is the current item in the iteration. - - *index* is the current index in the iteration - - *enumerable* is the enumerable object itself. - - It should return the a falsey value to include the item in the results. - - Note that in addition to a callback, you can also pass an optional target - object that will be set as "this" on the context. This is a good way - to give your iterator function access to the current object. - - @method reject - @param {Function} callback The callback to execute - @param {Object} [target] The target object to use - @return {Array} A rejected array. - */ - reject: function(callback, target) { - return this.filter(function() { - return !(apply(target, callback, arguments)); - }); - }, - - /** - Returns an array with just the items with the matched property. You - can pass an optional second argument with the target value. Otherwise - this will match any property that evaluates to `true`. - - @method filterBy - @param {String} key the property to test - @param {*} [value] optional value to test against. - @return {Array} filtered array - */ - filterBy: function(key, value) { - return this.filter(apply(this, iter, arguments)); - }, - - /** - Returns an array with just the items with the matched property. You - can pass an optional second argument with the target value. Otherwise - this will match any property that evaluates to `true`. - - @method filterProperty - @param {String} key the property to test - @param {String} [value] optional value to test against. - @return {Array} filtered array - @deprecated Use `filterBy` instead - */ - filterProperty: aliasMethod('filterBy'), - - /** - Returns an array with the items that do not have truthy values for - key. You can pass an optional second argument with the target value. Otherwise - this will match any property that evaluates to false. - - @method rejectBy - @param {String} key the property to test - @param {String} [value] optional value to test against. - @return {Array} rejected array - */ - rejectBy: function(key, value) { - var exactValue = function(item) { - return get(item, key) === value; - }; - - var hasValue = function(item) { - return !!get(item, key); - }; - - var use = (arguments.length === 2 ? exactValue : hasValue); - - return this.reject(use); - }, - - /** - Returns an array with the items that do not have truthy values for - key. You can pass an optional second argument with the target value. Otherwise - this will match any property that evaluates to false. - - @method rejectProperty - @param {String} key the property to test - @param {String} [value] optional value to test against. - @return {Array} rejected array - @deprecated Use `rejectBy` instead - */ - rejectProperty: aliasMethod('rejectBy'), - - /** - Returns the first item in the array for which the callback returns true. - This method works similar to the `filter()` method defined in JavaScript 1.6 - except that it will stop working on the array once a match is found. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(item, index, enumerable); - ``` - - - `item` is the current item in the iteration. - - `index` is the current index in the iteration. - - `enumerable` is the enumerable object itself. - - It should return the `true` to include the item in the results, `false` - otherwise. - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. This is a good way - to give your iterator function access to the current object. - - @method find - @param {Function} callback The callback to execute - @param {Object} [target] The target object to use - @return {Object} Found item or `undefined`. - */ - find: function(callback, target) { - var len = get(this, 'length'); - - if (target === undefined) { - target = null; - } - - var context = popCtx(); - var found = false; - var last = null; - var next, ret; - - for(var idx = 0; idx < len && !found; idx++) { - next = this.nextObject(idx, last, context); - - if (found = callback.call(target, next, idx, this)) { - ret = next; - } - - last = next; - } - - next = last = null; - context = pushCtx(context); - - return ret; - }, - - /** - Returns the first item with a property matching the passed value. You - can pass an optional second argument with the target value. Otherwise - this will match any property that evaluates to `true`. - - This method works much like the more generic `find()` method. - - @method findBy - @param {String} key the property to test - @param {String} [value] optional value to test against. - @return {Object} found item or `undefined` - */ - findBy: function(key, value) { - return this.find(apply(this, iter, arguments)); - }, - - /** - Returns the first item with a property matching the passed value. You - can pass an optional second argument with the target value. Otherwise - this will match any property that evaluates to `true`. - - This method works much like the more generic `find()` method. - - @method findProperty - @param {String} key the property to test - @param {String} [value] optional value to test against. - @return {Object} found item or `undefined` - @deprecated Use `findBy` instead - */ - findProperty: aliasMethod('findBy'), - - /** - Returns `true` if the passed function returns true for every item in the - enumeration. This corresponds with the `every()` method in JavaScript 1.6. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(item, index, enumerable); - ``` - - - `item` is the current item in the iteration. - - `index` is the current index in the iteration. - - `enumerable` is the enumerable object itself. - - It should return the `true` or `false`. - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. This is a good way - to give your iterator function access to the current object. - - Example Usage: - - ```javascript - if (people.every(isEngineer)) { - Paychecks.addBigBonus(); - } - ``` - - @method every - @param {Function} callback The callback to execute - @param {Object} [target] The target object to use - @return {Boolean} - */ - every: function(callback, target) { - return !this.find(function(x, idx, i) { - return !callback.call(target, x, idx, i); - }); - }, - - /** - @method everyBy - @param {String} key the property to test - @param {String} [value] optional value to test against. - @deprecated Use `isEvery` instead - @return {Boolean} - */ - everyBy: aliasMethod('isEvery'), - - /** - @method everyProperty - @param {String} key the property to test - @param {String} [value] optional value to test against. - @deprecated Use `isEvery` instead - @return {Boolean} - */ - everyProperty: aliasMethod('isEvery'), - - /** - Returns `true` if the passed property resolves to `true` for all items in - the enumerable. This method is often simpler/faster than using a callback. - - @method isEvery - @param {String} key the property to test - @param {String} [value] optional value to test against. - @return {Boolean} - @since 1.3.0 - */ - isEvery: function(key, value) { - return this.every(apply(this, iter, arguments)); - }, - - /** - Returns `true` if the passed function returns true for any item in the - enumeration. This corresponds with the `some()` method in JavaScript 1.6. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(item, index, enumerable); - ``` - - - `item` is the current item in the iteration. - - `index` is the current index in the iteration. - - `enumerable` is the enumerable object itself. - - It should return the `true` to include the item in the results, `false` - otherwise. - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. This is a good way - to give your iterator function access to the current object. - - Usage Example: - - ```javascript - if (people.any(isManager)) { - Paychecks.addBiggerBonus(); - } - ``` - - @method any - @param {Function} callback The callback to execute - @param {Object} [target] The target object to use - @return {Boolean} `true` if the passed function returns `true` for any item - */ - any: function(callback, target) { - var len = get(this, 'length'); - var context = popCtx(); - var found = false; - var last = null; - var next, idx; - - if (target === undefined) { - target = null; - } - - for (idx = 0; idx < len && !found; idx++) { - next = this.nextObject(idx, last, context); - found = callback.call(target, next, idx, this); - last = next; - } - - next = last = null; - context = pushCtx(context); - return found; - }, - - /** - Returns `true` if the passed function returns true for any item in the - enumeration. This corresponds with the `some()` method in JavaScript 1.6. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(item, index, enumerable); - ``` - - - `item` is the current item in the iteration. - - `index` is the current index in the iteration. - - `enumerable` is the enumerable object itself. - - It should return the `true` to include the item in the results, `false` - otherwise. - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. This is a good way - to give your iterator function access to the current object. - - Usage Example: - - ```javascript - if (people.some(isManager)) { - Paychecks.addBiggerBonus(); - } - ``` - - @method some - @param {Function} callback The callback to execute - @param {Object} [target] The target object to use - @return {Boolean} `true` if the passed function returns `true` for any item - @deprecated Use `any` instead - */ - some: aliasMethod('any'), - - /** - Returns `true` if the passed property resolves to `true` for any item in - the enumerable. This method is often simpler/faster than using a callback. - - @method isAny - @param {String} key the property to test - @param {String} [value] optional value to test against. - @return {Boolean} - @since 1.3.0 - */ - isAny: function(key, value) { - return this.any(apply(this, iter, arguments)); - }, - - /** - @method anyBy - @param {String} key the property to test - @param {String} [value] optional value to test against. - @return {Boolean} - @deprecated Use `isAny` instead - */ - anyBy: aliasMethod('isAny'), - - /** - @method someProperty - @param {String} key the property to test - @param {String} [value] optional value to test against. - @return {Boolean} - @deprecated Use `isAny` instead - */ - someProperty: aliasMethod('isAny'), - - /** - This will combine the values of the enumerator into a single value. It - is a useful way to collect a summary value from an enumeration. This - corresponds to the `reduce()` method defined in JavaScript 1.8. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(previousValue, item, index, enumerable); - ``` - - - `previousValue` is the value returned by the last call to the iterator. - - `item` is the current item in the iteration. - - `index` is the current index in the iteration. - - `enumerable` is the enumerable object itself. - - Return the new cumulative value. - - In addition to the callback you can also pass an `initialValue`. An error - will be raised if you do not pass an initial value and the enumerator is - empty. - - Note that unlike the other methods, this method does not allow you to - pass a target object to set as this for the callback. It's part of the - spec. Sorry. - - @method reduce - @param {Function} callback The callback to execute - @param {Object} initialValue Initial value for the reduce - @param {String} reducerProperty internal use only. - @return {Object} The reduced value. - */ - reduce: function(callback, initialValue, reducerProperty) { - if (typeof callback !== 'function') { - throw new TypeError(); - } - - var ret = initialValue; - - this.forEach(function(item, i) { - ret = callback(ret, item, i, this, reducerProperty); - }, this); - - return ret; - }, - - /** - Invokes the named method on every object in the receiver that - implements it. This method corresponds to the implementation in - Prototype 1.6. - - @method invoke - @param {String} methodName the name of the method - @param {Object...} args optional arguments to pass as well. - @return {Array} return values from calling invoke. - */ - invoke: function(methodName) { - var ret = Ember.A(); - var args; - - if (arguments.length > 1) { - args = a_slice.call(arguments, 1); - } - - this.forEach(function(x, idx) { - var method = x && x[methodName]; - - if ('function' === typeof method) { - ret[idx] = args ? apply(x, method, args) : x[methodName](); - } - }, this); - - return ret; - }, - - /** - Simply converts the enumerable into a genuine array. The order is not - guaranteed. Corresponds to the method implemented by Prototype. - - @method toArray - @return {Array} the enumerable as an array. - */ - toArray: function() { - var ret = Ember.A(); - - this.forEach(function(o, idx) { - ret[idx] = o; - }); - - return ret; - }, - - /** - Returns a copy of the array with all `null` and `undefined` elements removed. - - ```javascript - var arr = ['a', null, 'c', undefined]; - arr.compact(); // ['a', 'c'] - ``` - - @method compact - @return {Array} the array without null and undefined elements. - */ - compact: function() { - return this.filter(function(value) { - return value != null; - }); - }, - - /** - Returns a new enumerable that excludes the passed value. The default - implementation returns an array regardless of the receiver type unless - the receiver does not contain the value. - - ```javascript - var arr = ['a', 'b', 'a', 'c']; - arr.without('a'); // ['b', 'c'] - ``` - - @method without - @param {Object} value - @return {Ember.Enumerable} - */ - without: function(value) { - if (!this.contains(value)) { - return this; // nothing to do - } - - var ret = Ember.A(); - - this.forEach(function(k) { - if (k !== value) { - ret[ret.length] = k; - } - }); - - return ret; - }, - - /** - Returns a new enumerable that contains only unique values. The default - implementation returns an array regardless of the receiver type. - - ```javascript - var arr = ['a', 'a', 'b', 'b']; - arr.uniq(); // ['a', 'b'] - ``` - - This only works on primitive data types, e.g. Strings, Numbers, etc. - - @method uniq - @return {Ember.Enumerable} - */ - uniq: function() { - var ret = Ember.A(); - - this.forEach(function(k) { - if (indexOf(ret, k) < 0) { - ret.push(k); - } - }); - - return ret; - }, - - /** - This property will trigger anytime the enumerable's content changes. - You can observe this property to be notified of changes to the enumerables - content. - - For plain enumerables, this property is read only. `Array` overrides - this method. - - @property [] - @type Array - @return this - */ - '[]': computed(function(key, value) { - return this; - }), - - // .......................................................... - // ENUMERABLE OBSERVERS - // - - /** - Registers an enumerable observer. Must implement `Ember.EnumerableObserver` - mixin. - - @method addEnumerableObserver - @param {Object} target - @param {Hash} [opts] - @return this - */ - addEnumerableObserver: function(target, opts) { - var willChange = (opts && opts.willChange) || 'enumerableWillChange'; - var didChange = (opts && opts.didChange) || 'enumerableDidChange'; - var hasObservers = get(this, 'hasEnumerableObservers'); - - if (!hasObservers) { - propertyWillChange(this, 'hasEnumerableObservers'); - } - - addListener(this, '@enumerable:before', target, willChange); - addListener(this, '@enumerable:change', target, didChange); - - if (!hasObservers) { - propertyDidChange(this, 'hasEnumerableObservers'); - } - - return this; - }, - - /** - Removes a registered enumerable observer. - - @method removeEnumerableObserver - @param {Object} target - @param {Hash} [opts] - @return this - */ - removeEnumerableObserver: function(target, opts) { - var willChange = (opts && opts.willChange) || 'enumerableWillChange'; - var didChange = (opts && opts.didChange) || 'enumerableDidChange'; - var hasObservers = get(this, 'hasEnumerableObservers'); - - if (hasObservers) { - propertyWillChange(this, 'hasEnumerableObservers'); - } - - removeListener(this, '@enumerable:before', target, willChange); - removeListener(this, '@enumerable:change', target, didChange); - - if (hasObservers) { - propertyDidChange(this, 'hasEnumerableObservers'); - } - - return this; - }, - - /** - Becomes true whenever the array currently has observers watching changes - on the array. - - @property hasEnumerableObservers - @type Boolean - */ - hasEnumerableObservers: computed(function() { - return hasListeners(this, '@enumerable:change') || hasListeners(this, '@enumerable:before'); - }), - - - /** - Invoke this method just before the contents of your enumerable will - change. You can either omit the parameters completely or pass the objects - to be removed or added if available or just a count. - - @method enumerableContentWillChange - @param {Ember.Enumerable|Number} removing An enumerable of the objects to - be removed or the number of items to be removed. - @param {Ember.Enumerable|Number} adding An enumerable of the objects to be - added or the number of items to be added. - @chainable - */ - enumerableContentWillChange: function(removing, adding) { - var removeCnt, addCnt, hasDelta; - - if ('number' === typeof removing) { - removeCnt = removing; - } else if (removing) { - removeCnt = get(removing, 'length'); - } else { - removeCnt = removing = -1; - } - - if ('number' === typeof adding) { - addCnt = adding; - } else if (adding) { - addCnt = get(adding,'length'); - } else { - addCnt = adding = -1; - } - - hasDelta = addCnt < 0 || removeCnt < 0 || addCnt - removeCnt !== 0; - - if (removing === -1) { - removing = null; - } - - if (adding === -1) { - adding = null; - } - - propertyWillChange(this, '[]'); - - if (hasDelta) { - propertyWillChange(this, 'length'); - } - - sendEvent(this, '@enumerable:before', [this, removing, adding]); - - return this; - }, - - /** - Invoke this method when the contents of your enumerable has changed. - This will notify any observers watching for content changes. If you are - implementing an ordered enumerable (such as an array), also pass the - start and end values where the content changed so that it can be used to - notify range observers. - - @method enumerableContentDidChange - @param {Ember.Enumerable|Number} removing An enumerable of the objects to - be removed or the number of items to be removed. - @param {Ember.Enumerable|Number} adding An enumerable of the objects to - be added or the number of items to be added. - @chainable - */ - enumerableContentDidChange: function(removing, adding) { - var removeCnt, addCnt, hasDelta; - - if ('number' === typeof removing) { - removeCnt = removing; - } else if (removing) { - removeCnt = get(removing, 'length'); - } else { - removeCnt = removing = -1; - } - - if ('number' === typeof adding) { - addCnt = adding; - } else if (adding) { - addCnt = get(adding, 'length'); - } else { - addCnt = adding = -1; - } - - hasDelta = addCnt < 0 || removeCnt < 0 || addCnt - removeCnt !== 0; - - if (removing === -1) { - removing = null; - } - - if (adding === -1) { - adding = null; - } - - sendEvent(this, '@enumerable:change', [this, removing, adding]); - - if (hasDelta) { - propertyDidChange(this, 'length'); - } - - propertyDidChange(this, '[]'); - - return this ; - }, - - /** - Converts the enumerable into an array and sorts by the keys - specified in the argument. - - You may provide multiple arguments to sort by multiple properties. - - @method sortBy - @param {String} property name(s) to sort on - @return {Array} The sorted array. - @since 1.2.0 - */ - sortBy: function() { - var sortKeys = arguments; - - return this.toArray().sort(function(a, b) { - for(var i = 0; i < sortKeys.length; i++) { - var key = sortKeys[i]; - var propA = get(a, key); - var propB = get(b, key); - // return 1 or -1 else continue to the next sortKey - var compareValue = compare(propA, propB); - - if (compareValue) { - return compareValue; - } - } - return 0; - }); - } - }); - }); -enifed("ember-runtime/mixins/evented", - ["ember-metal/mixin","ember-metal/events","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Mixin = __dependency1__.Mixin; - var addListener = __dependency2__.addListener; - var removeListener = __dependency2__.removeListener; - var hasListeners = __dependency2__.hasListeners; - var sendEvent = __dependency2__.sendEvent; - - /** - @module ember - @submodule ember-runtime - */ - - /** - This mixin allows for Ember objects to subscribe to and emit events. - - ```javascript - App.Person = Ember.Object.extend(Ember.Evented, { - greet: function() { - // ... - this.trigger('greet'); - } - }); - - var person = App.Person.create(); - - person.on('greet', function() { - console.log('Our person has greeted'); - }); - - person.greet(); - - // outputs: 'Our person has greeted' - ``` - - You can also chain multiple event subscriptions: - - ```javascript - person.on('greet', function() { - console.log('Our person has greeted'); - }).one('greet', function() { - console.log('Offer one-time special'); - }).off('event', this, forgetThis); - ``` - - @class Evented - @namespace Ember - */ - __exports__["default"] = Mixin.create({ - - /** - Subscribes to a named event with given function. - - ```javascript - person.on('didLoad', function() { - // fired once the person has loaded - }); - ``` - - An optional target can be passed in as the 2nd argument that will - be set as the "this" for the callback. This is a good way to give your - function access to the object triggering the event. When the target - parameter is used the callback becomes the third argument. - - @method on - @param {String} name The name of the event - @param {Object} [target] The "this" binding for the callback - @param {Function} method The callback to execute - @return this - */ - on: function(name, target, method) { - addListener(this, name, target, method); - return this; - }, - - /** - Subscribes a function to a named event and then cancels the subscription - after the first time the event is triggered. It is good to use ``one`` when - you only care about the first time an event has taken place. - - This function takes an optional 2nd argument that will become the "this" - value for the callback. If this argument is passed then the 3rd argument - becomes the function. - - @method one - @param {String} name The name of the event - @param {Object} [target] The "this" binding for the callback - @param {Function} method The callback to execute - @return this - */ - one: function(name, target, method) { - if (!method) { - method = target; - target = null; - } - - addListener(this, name, target, method, true); - return this; - }, - - /** - Triggers a named event for the object. Any additional arguments - will be passed as parameters to the functions that are subscribed to the - event. - - ```javascript - person.on('didEat', function(food) { - console.log('person ate some ' + food); - }); - - person.trigger('didEat', 'broccoli'); - - // outputs: person ate some broccoli - ``` - @method trigger - @param {String} name The name of the event - @param {Object...} args Optional arguments to pass on - */ - trigger: function(name) { - var length = arguments.length; - var args = new Array(length - 1); - - for (var i = 1; i < length; i++) { - args[i - 1] = arguments[i]; - } - - sendEvent(this, name, args); - }, - - /** - Cancels subscription for given name, target, and method. - - @method off - @param {String} name The name of the event - @param {Object} target The target of the subscription - @param {Function} method The function of the subscription - @return this - */ - off: function(name, target, method) { - removeListener(this, name, target, method); - return this; - }, - - /** - Checks to see if object has any subscriptions for named event. - - @method has - @param {String} name The name of the event - @return {Boolean} does the object have a subscription for event - */ - has: function(name) { - return hasListeners(this, name); - } - }); - }); -enifed("ember-runtime/mixins/freezable", - ["ember-metal/mixin","ember-metal/property_get","ember-metal/property_set","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - var Mixin = __dependency1__.Mixin; - var get = __dependency2__.get; - var set = __dependency3__.set; - - /** - The `Ember.Freezable` mixin implements some basic methods for marking an - object as frozen. Once an object is frozen it should be read only. No changes - may be made the internal state of the object. - - ## Enforcement - - To fully support freezing in your subclass, you must include this mixin and - override any method that might alter any property on the object to instead - raise an exception. You can check the state of an object by checking the - `isFrozen` property. - - Although future versions of JavaScript may support language-level freezing - object objects, that is not the case today. Even if an object is freezable, - it is still technically possible to modify the object, even though it could - break other parts of your application that do not expect a frozen object to - change. It is, therefore, very important that you always respect the - `isFrozen` property on all freezable objects. - - ## Example Usage - - The example below shows a simple object that implement the `Ember.Freezable` - protocol. - - ```javascript - Contact = Ember.Object.extend(Ember.Freezable, { - firstName: null, - lastName: null, - - // swaps the names - swapNames: function() { - if (this.get('isFrozen')) throw Ember.FROZEN_ERROR; - var tmp = this.get('firstName'); - this.set('firstName', this.get('lastName')); - this.set('lastName', tmp); - return this; - } - - }); - - c = Contact.create({ firstName: "John", lastName: "Doe" }); - c.swapNames(); // returns c - c.freeze(); - c.swapNames(); // EXCEPTION - ``` - - ## Copying - - Usually the `Ember.Freezable` protocol is implemented in cooperation with the - `Ember.Copyable` protocol, which defines a `frozenCopy()` method that will - return a frozen object, if the object implements this method as well. - - @class Freezable - @namespace Ember - @since Ember 0.9 - */ - var Freezable = Mixin.create({ - - /** - Set to `true` when the object is frozen. Use this property to detect - whether your object is frozen or not. - - @property isFrozen - @type Boolean - */ - isFrozen: false, - - /** - Freezes the object. Once this method has been called the object should - no longer allow any properties to be edited. - - @method freeze - @return {Object} receiver - */ - freeze: function() { - if (get(this, 'isFrozen')) return this; - set(this, 'isFrozen', true); - return this; - } - - }); - __exports__.Freezable = Freezable; - var FROZEN_ERROR = "Frozen object cannot be modified."; - __exports__.FROZEN_ERROR = FROZEN_ERROR; - }); -enifed("ember-runtime/mixins/mutable_array", - ["ember-metal/property_get","ember-metal/utils","ember-metal/error","ember-metal/mixin","ember-runtime/mixins/array","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - - // require('ember-runtime/mixins/array'); - // require('ember-runtime/mixins/mutable_enumerable'); - - // .......................................................... - // CONSTANTS - // - - var OUT_OF_RANGE_EXCEPTION = "Index out of range"; - var EMPTY = []; - - // .......................................................... - // HELPERS - // - - var get = __dependency1__.get; - var isArray = __dependency2__.isArray; - var EmberError = __dependency3__["default"]; - var Mixin = __dependency4__.Mixin; - var required = __dependency4__.required; - var EmberArray = __dependency5__["default"]; - var MutableEnumerable = __dependency6__["default"]; - var Enumerable = __dependency7__["default"]; - /** - This mixin defines the API for modifying array-like objects. These methods - can be applied only to a collection that keeps its items in an ordered set. - It builds upon the Array mixin and adds methods to modify the array. - Concrete implementations of this class include ArrayProxy and ArrayController. - - It is important to use the methods in this class to modify arrays so that - changes are observable. This allows the binding system in Ember to function - correctly. - - - Note that an Array can change even if it does not implement this mixin. - For example, one might implement a SparseArray that cannot be directly - modified, but if its underlying enumerable changes, it will change also. - - @class MutableArray - @namespace Ember - @uses Ember.Array - @uses Ember.MutableEnumerable - */ - __exports__["default"] = Mixin.create(EmberArray, MutableEnumerable, { - - /** - __Required.__ You must implement this method to apply this mixin. - - This is one of the primitives you must implement to support `Ember.Array`. - You should replace amt objects started at idx with the objects in the - passed array. You should also call `this.enumerableContentDidChange()` - - @method replace - @param {Number} idx Starting index in the array to replace. If - idx >= length, then append to the end of the array. - @param {Number} amt Number of elements that should be removed from - the array, starting at *idx*. - @param {Array} objects An array of zero or more objects that should be - inserted into the array at *idx* - */ - replace: required(), - - /** - Remove all elements from the array. This is useful if you - want to reuse an existing array without having to recreate it. - - ```javascript - var colors = ["red", "green", "blue"]; - color.length(); // 3 - colors.clear(); // [] - colors.length(); // 0 - ``` - - @method clear - @return {Ember.Array} An empty Array. - */ - clear: function () { - var len = get(this, 'length'); - if (len === 0) return this; - this.replace(0, len, EMPTY); - return this; - }, - - /** - This will use the primitive `replace()` method to insert an object at the - specified index. - - ```javascript - var colors = ["red", "green", "blue"]; - colors.insertAt(2, "yellow"); // ["red", "green", "yellow", "blue"] - colors.insertAt(5, "orange"); // Error: Index out of range - ``` - - @method insertAt - @param {Number} idx index of insert the object at. - @param {Object} object object to insert - @return {Ember.Array} receiver - */ - insertAt: function(idx, object) { - if (idx > get(this, 'length')) throw new EmberError(OUT_OF_RANGE_EXCEPTION); - this.replace(idx, 0, [object]); - return this; - }, - - /** - Remove an object at the specified index using the `replace()` primitive - method. You can pass either a single index, or a start and a length. - - If you pass a start and length that is beyond the - length this method will throw an `OUT_OF_RANGE_EXCEPTION`. - - ```javascript - var colors = ["red", "green", "blue", "yellow", "orange"]; - colors.removeAt(0); // ["green", "blue", "yellow", "orange"] - colors.removeAt(2, 2); // ["green", "blue"] - colors.removeAt(4, 2); // Error: Index out of range - ``` - - @method removeAt - @param {Number} start index, start of range - @param {Number} len length of passing range - @return {Ember.Array} receiver - */ - removeAt: function(start, len) { - if ('number' === typeof start) { - - if ((start < 0) || (start >= get(this, 'length'))) { - throw new EmberError(OUT_OF_RANGE_EXCEPTION); - } - - // fast case - if (len === undefined) len = 1; - this.replace(start, len, EMPTY); - } - - return this; - }, - - /** - Push the object onto the end of the array. Works just like `push()` but it - is KVO-compliant. - - ```javascript - var colors = ["red", "green"]; - colors.pushObject("black"); // ["red", "green", "black"] - colors.pushObject(["yellow"]); // ["red", "green", ["yellow"]] - ``` - - @method pushObject - @param {*} obj object to push - @return object same object passed as a param - */ - pushObject: function(obj) { - this.insertAt(get(this, 'length'), obj); - return obj; - }, - - /** - Add the objects in the passed numerable to the end of the array. Defers - notifying observers of the change until all objects are added. - - ```javascript - var colors = ["red"]; - colors.pushObjects(["yellow", "orange"]); // ["red", "yellow", "orange"] - ``` - - @method pushObjects - @param {Ember.Enumerable} objects the objects to add - @return {Ember.Array} receiver - */ - pushObjects: function(objects) { - if (!(Enumerable.detect(objects) || isArray(objects))) { - throw new TypeError("Must pass Ember.Enumerable to Ember.MutableArray#pushObjects"); - } - this.replace(get(this, 'length'), 0, objects); - return this; - }, - - /** - Pop object from array or nil if none are left. Works just like `pop()` but - it is KVO-compliant. - - ```javascript - var colors = ["red", "green", "blue"]; - colors.popObject(); // "blue" - console.log(colors); // ["red", "green"] - ``` - - @method popObject - @return object - */ - popObject: function() { - var len = get(this, 'length'); - if (len === 0) return null; - - var ret = this.objectAt(len-1); - this.removeAt(len-1, 1); - return ret; - }, - - /** - Shift an object from start of array or nil if none are left. Works just - like `shift()` but it is KVO-compliant. - - ```javascript - var colors = ["red", "green", "blue"]; - colors.shiftObject(); // "red" - console.log(colors); // ["green", "blue"] - ``` - - @method shiftObject - @return object - */ - shiftObject: function() { - if (get(this, 'length') === 0) return null; - var ret = this.objectAt(0); - this.removeAt(0); - return ret; - }, - - /** - Unshift an object to start of array. Works just like `unshift()` but it is - KVO-compliant. - - ```javascript - var colors = ["red"]; - colors.unshiftObject("yellow"); // ["yellow", "red"] - colors.unshiftObject(["black"]); // [["black"], "yellow", "red"] - ``` - - @method unshiftObject - @param {*} obj object to unshift - @return object same object passed as a param - */ - unshiftObject: function(obj) { - this.insertAt(0, obj); - return obj; - }, - - /** - Adds the named objects to the beginning of the array. Defers notifying - observers until all objects have been added. - - ```javascript - var colors = ["red"]; - colors.unshiftObjects(["black", "white"]); // ["black", "white", "red"] - colors.unshiftObjects("yellow"); // Type Error: 'undefined' is not a function - ``` - - @method unshiftObjects - @param {Ember.Enumerable} objects the objects to add - @return {Ember.Array} receiver - */ - unshiftObjects: function(objects) { - this.replace(0, 0, objects); - return this; - }, - - /** - Reverse objects in the array. Works just like `reverse()` but it is - KVO-compliant. - - @method reverseObjects - @return {Ember.Array} receiver - */ - reverseObjects: function() { - var len = get(this, 'length'); - if (len === 0) return this; - var objects = this.toArray().reverse(); - this.replace(0, len, objects); - return this; - }, - - /** - Replace all the receiver's content with content of the argument. - If argument is an empty array receiver will be cleared. - - ```javascript - var colors = ["red", "green", "blue"]; - colors.setObjects(["black", "white"]); // ["black", "white"] - colors.setObjects([]); // [] - ``` - - @method setObjects - @param {Ember.Array} objects array whose content will be used for replacing - the content of the receiver - @return {Ember.Array} receiver with the new content - */ - setObjects: function(objects) { - if (objects.length === 0) return this.clear(); - - var len = get(this, 'length'); - this.replace(0, len, objects); - return this; - }, - - // .......................................................... - // IMPLEMENT Ember.MutableEnumerable - // - - /** - Remove all occurrences of an object in the array. - - ```javascript - var cities = ["Chicago", "Berlin", "Lima", "Chicago"]; - cities.removeObject("Chicago"); // ["Berlin", "Lima"] - cities.removeObject("Lima"); // ["Berlin"] - cities.removeObject("Tokyo") // ["Berlin"] - ``` - - @method removeObject - @param {*} obj object to remove - @return {Ember.Array} receiver - */ - removeObject: function(obj) { - var loc = get(this, 'length') || 0; - while(--loc >= 0) { - var curObject = this.objectAt(loc); - if (curObject === obj) this.removeAt(loc); - } - return this; - }, - - /** - Push the object onto the end of the array if it is not already - present in the array. - - ```javascript - var cities = ["Chicago", "Berlin"]; - cities.addObject("Lima"); // ["Chicago", "Berlin", "Lima"] - cities.addObject("Berlin"); // ["Chicago", "Berlin", "Lima"] - ``` - - @method addObject - @param {*} obj object to add, if not already present - @return {Ember.Array} receiver - */ - addObject: function(obj) { - if (!this.contains(obj)) this.pushObject(obj); - return this; - } - - }); - }); -enifed("ember-runtime/mixins/mutable_enumerable", - ["ember-metal/enumerable_utils","ember-runtime/mixins/enumerable","ember-metal/mixin","ember-metal/property_events","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var forEach = __dependency1__.forEach; - var Enumerable = __dependency2__["default"]; - var Mixin = __dependency3__.Mixin; - var required = __dependency3__.required; - var beginPropertyChanges = __dependency4__.beginPropertyChanges; - var endPropertyChanges = __dependency4__.endPropertyChanges; - - /** - @module ember - @submodule ember-runtime - */ - - /** - This mixin defines the API for modifying generic enumerables. These methods - can be applied to an object regardless of whether it is ordered or - unordered. - - Note that an Enumerable can change even if it does not implement this mixin. - For example, a MappedEnumerable cannot be directly modified but if its - underlying enumerable changes, it will change also. - - ## Adding Objects - - To add an object to an enumerable, use the `addObject()` method. This - method will only add the object to the enumerable if the object is not - already present and is of a type supported by the enumerable. - - ```javascript - set.addObject(contact); - ``` - - ## Removing Objects - - To remove an object from an enumerable, use the `removeObject()` method. This - will only remove the object if it is present in the enumerable, otherwise - this method has no effect. - - ```javascript - set.removeObject(contact); - ``` - - ## Implementing In Your Own Code - - If you are implementing an object and want to support this API, just include - this mixin in your class and implement the required methods. In your unit - tests, be sure to apply the Ember.MutableEnumerableTests to your object. - - @class MutableEnumerable - @namespace Ember - @uses Ember.Enumerable - */ - __exports__["default"] = Mixin.create(Enumerable, { - - /** - __Required.__ You must implement this method to apply this mixin. - - Attempts to add the passed object to the receiver if the object is not - already present in the collection. If the object is present, this method - has no effect. - - If the passed object is of a type not supported by the receiver, - then this method should raise an exception. - - @method addObject - @param {Object} object The object to add to the enumerable. - @return {Object} the passed object - */ - addObject: required(Function), - - /** - Adds each object in the passed enumerable to the receiver. - - @method addObjects - @param {Ember.Enumerable} objects the objects to add. - @return {Object} receiver - */ - addObjects: function(objects) { - beginPropertyChanges(this); - forEach(objects, function(obj) { this.addObject(obj); }, this); - endPropertyChanges(this); - return this; - }, - - /** - __Required.__ You must implement this method to apply this mixin. - - Attempts to remove the passed object from the receiver collection if the - object is present in the collection. If the object is not present, - this method has no effect. - - If the passed object is of a type not supported by the receiver, - then this method should raise an exception. - - @method removeObject - @param {Object} object The object to remove from the enumerable. - @return {Object} the passed object - */ - removeObject: required(Function), - - - /** - Removes each object in the passed enumerable from the receiver. - - @method removeObjects - @param {Ember.Enumerable} objects the objects to remove - @return {Object} receiver - */ - removeObjects: function(objects) { - beginPropertyChanges(this); - for (var i = objects.length - 1; i >= 0; i--) { - this.removeObject(objects[i]); - } - endPropertyChanges(this); - return this; - } - }); - }); -enifed("ember-runtime/mixins/observable", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/get_properties","ember-metal/set_properties","ember-metal/mixin","ember-metal/events","ember-metal/property_events","ember-metal/observer","ember-metal/computed","ember-metal/is_none","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - var Ember = __dependency1__["default"]; - // Ember.assert - - var get = __dependency2__.get; - var getWithDefault = __dependency2__.getWithDefault; - var set = __dependency3__.set; - var apply = __dependency4__.apply; - var getProperties = __dependency5__["default"]; - var setProperties = __dependency6__["default"]; - var Mixin = __dependency7__.Mixin; - var hasListeners = __dependency8__.hasListeners; - var beginPropertyChanges = __dependency9__.beginPropertyChanges; - var propertyWillChange = __dependency9__.propertyWillChange; - var propertyDidChange = __dependency9__.propertyDidChange; - var endPropertyChanges = __dependency9__.endPropertyChanges; - var addObserver = __dependency10__.addObserver; - var addBeforeObserver = __dependency10__.addBeforeObserver; - var removeObserver = __dependency10__.removeObserver; - var observersFor = __dependency10__.observersFor; - var cacheFor = __dependency11__.cacheFor; - var isNone = __dependency12__["default"]; - - - var slice = Array.prototype.slice; - /** - ## Overview - - This mixin provides properties and property observing functionality, core - features of the Ember object model. - - Properties and observers allow one object to observe changes to a - property on another object. This is one of the fundamental ways that - models, controllers and views communicate with each other in an Ember - application. - - Any object that has this mixin applied can be used in observer - operations. That includes `Ember.Object` and most objects you will - interact with as you write your Ember application. - - Note that you will not generally apply this mixin to classes yourself, - but you will use the features provided by this module frequently, so it - is important to understand how to use it. - - ## Using `get()` and `set()` - - Because of Ember's support for bindings and observers, you will always - access properties using the get method, and set properties using the - set method. This allows the observing objects to be notified and - computed properties to be handled properly. - - More documentation about `get` and `set` are below. - - ## Observing Property Changes - - You typically observe property changes simply by adding the `observes` - call to the end of your method declarations in classes that you write. - For example: - - ```javascript - Ember.Object.extend({ - valueObserver: function() { - // Executes whenever the "value" property changes - }.observes('value') - }); - ``` - - Although this is the most common way to add an observer, this capability - is actually built into the `Ember.Object` class on top of two methods - defined in this mixin: `addObserver` and `removeObserver`. You can use - these two methods to add and remove observers yourself if you need to - do so at runtime. - - To add an observer for a property, call: - - ```javascript - object.addObserver('propertyKey', targetObject, targetAction) - ``` - - This will call the `targetAction` method on the `targetObject` whenever - the value of the `propertyKey` changes. - - Note that if `propertyKey` is a computed property, the observer will be - called when any of the property dependencies are changed, even if the - resulting value of the computed property is unchanged. This is necessary - because computed properties are not computed until `get` is called. - - @class Observable - @namespace Ember - */ - __exports__["default"] = Mixin.create({ - - /** - Retrieves the value of a property from the object. - - This method is usually similar to using `object[keyName]` or `object.keyName`, - however it supports both computed properties and the unknownProperty - handler. - - Because `get` unifies the syntax for accessing all these kinds - of properties, it can make many refactorings easier, such as replacing a - simple property with a computed property, or vice versa. - - ### Computed Properties - - Computed properties are methods defined with the `property` modifier - declared at the end, such as: - - ```javascript - fullName: function() { - return this.get('firstName') + ' ' + this.get('lastName'); - }.property('firstName', 'lastName') - ``` - - When you call `get` on a computed property, the function will be - called and the return value will be returned instead of the function - itself. - - ### Unknown Properties - - Likewise, if you try to call `get` on a property whose value is - `undefined`, the `unknownProperty()` method will be called on the object. - If this method returns any value other than `undefined`, it will be returned - instead. This allows you to implement "virtual" properties that are - not defined upfront. - - @method get - @param {String} keyName The property to retrieve - @return {Object} The property value or undefined. - */ - get: function(keyName) { - return get(this, keyName); - }, - - /** - To get the values of multiple properties at once, call `getProperties` - with a list of strings or an array: - - ```javascript - record.getProperties('firstName', 'lastName', 'zipCode'); - // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } - ``` - - is equivalent to: - - ```javascript - record.getProperties(['firstName', 'lastName', 'zipCode']); - // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } - ``` - - @method getProperties - @param {String...|Array} list of keys to get - @return {Hash} - */ - getProperties: function() { - return apply(null, getProperties, [this].concat(slice.call(arguments))); - }, - - /** - Sets the provided key or path to the value. - - This method is generally very similar to calling `object[key] = value` or - `object.key = value`, except that it provides support for computed - properties, the `setUnknownProperty()` method and property observers. - - ### Computed Properties - - If you try to set a value on a key that has a computed property handler - defined (see the `get()` method for an example), then `set()` will call - that method, passing both the value and key instead of simply changing - the value itself. This is useful for those times when you need to - implement a property that is composed of one or more member - properties. - - ### Unknown Properties - - If you try to set a value on a key that is undefined in the target - object, then the `setUnknownProperty()` handler will be called instead. This - gives you an opportunity to implement complex "virtual" properties that - are not predefined on the object. If `setUnknownProperty()` returns - undefined, then `set()` will simply set the value on the object. - - ### Property Observers - - In addition to changing the property, `set()` will also register a property - change with the object. Unless you have placed this call inside of a - `beginPropertyChanges()` and `endPropertyChanges(),` any "local" observers - (i.e. observer methods declared on the same object), will be called - immediately. Any "remote" observers (i.e. observer methods declared on - another object) will be placed in a queue and called at a later time in a - coalesced manner. - - ### Chaining - - In addition to property changes, `set()` returns the value of the object - itself so you can do chaining like this: - - ```javascript - record.set('firstName', 'Charles').set('lastName', 'Jolley'); - ``` - - @method set - @param {String} keyName The property to set - @param {Object} value The value to set or `null`. - @return {Ember.Observable} - */ - set: function(keyName, value) { - set(this, keyName, value); - return this; - }, - - - /** - Sets a list of properties at once. These properties are set inside - a single `beginPropertyChanges` and `endPropertyChanges` batch, so - observers will be buffered. - - ```javascript - record.setProperties({ firstName: 'Charles', lastName: 'Jolley' }); - ``` - - @method setProperties - @param {Hash} hash the hash of keys and values to set - @return {Ember.Observable} - */ - setProperties: function(hash) { - return setProperties(this, hash); - }, - - /** - Begins a grouping of property changes. - - You can use this method to group property changes so that notifications - will not be sent until the changes are finished. If you plan to make a - large number of changes to an object at one time, you should call this - method at the beginning of the changes to begin deferring change - notifications. When you are done making changes, call - `endPropertyChanges()` to deliver the deferred change notifications and end - deferring. - - @method beginPropertyChanges - @return {Ember.Observable} - */ - beginPropertyChanges: function() { - beginPropertyChanges(); - return this; - }, - - /** - Ends a grouping of property changes. - - You can use this method to group property changes so that notifications - will not be sent until the changes are finished. If you plan to make a - large number of changes to an object at one time, you should call - `beginPropertyChanges()` at the beginning of the changes to defer change - notifications. When you are done making changes, call this method to - deliver the deferred change notifications and end deferring. - - @method endPropertyChanges - @return {Ember.Observable} - */ - endPropertyChanges: function() { - endPropertyChanges(); - return this; - }, - - /** - Notify the observer system that a property is about to change. - - Sometimes you need to change a value directly or indirectly without - actually calling `get()` or `set()` on it. In this case, you can use this - method and `propertyDidChange()` instead. Calling these two methods - together will notify all observers that the property has potentially - changed value. - - Note that you must always call `propertyWillChange` and `propertyDidChange` - as a pair. If you do not, it may get the property change groups out of - order and cause notifications to be delivered more often than you would - like. - - @method propertyWillChange - @param {String} keyName The property key that is about to change. - @return {Ember.Observable} - */ - propertyWillChange: function(keyName) { - propertyWillChange(this, keyName); - return this; - }, - - /** - Notify the observer system that a property has just changed. - - Sometimes you need to change a value directly or indirectly without - actually calling `get()` or `set()` on it. In this case, you can use this - method and `propertyWillChange()` instead. Calling these two methods - together will notify all observers that the property has potentially - changed value. - - Note that you must always call `propertyWillChange` and `propertyDidChange` - as a pair. If you do not, it may get the property change groups out of - order and cause notifications to be delivered more often than you would - like. - - @method propertyDidChange - @param {String} keyName The property key that has just changed. - @return {Ember.Observable} - */ - propertyDidChange: function(keyName) { - propertyDidChange(this, keyName); - return this; - }, - - /** - Convenience method to call `propertyWillChange` and `propertyDidChange` in - succession. - - @method notifyPropertyChange - @param {String} keyName The property key to be notified about. - @return {Ember.Observable} - */ - notifyPropertyChange: function(keyName) { - this.propertyWillChange(keyName); - this.propertyDidChange(keyName); - return this; - }, - - addBeforeObserver: function(key, target, method) { - Ember.deprecate('Before observers are deprecated and will be removed in a future release. If you want to keep track of previous values you have to implement it yourself.', false, { url: 'http://emberjs.com/guides/deprecations/#toc_deprecate-beforeobservers' }); - addBeforeObserver(this, key, target, method); - }, - - /** - Adds an observer on a property. - - This is the core method used to register an observer for a property. - - Once you call this method, any time the key's value is set, your observer - will be notified. Note that the observers are triggered any time the - value is set, regardless of whether it has actually changed. Your - observer should be prepared to handle that. - - You can also pass an optional context parameter to this method. The - context will be passed to your observer method whenever it is triggered. - Note that if you add the same target/method pair on a key multiple times - with different context parameters, your observer will only be called once - with the last context you passed. - - ### Observer Methods - - Observer methods you pass should generally have the following signature if - you do not pass a `context` parameter: - - ```javascript - fooDidChange: function(sender, key, value, rev) { }; - ``` - - The sender is the object that changed. The key is the property that - changes. The value property is currently reserved and unused. The rev - is the last property revision of the object when it changed, which you can - use to detect if the key value has really changed or not. - - If you pass a `context` parameter, the context will be passed before the - revision like so: - - ```javascript - fooDidChange: function(sender, key, value, context, rev) { }; - ``` - - Usually you will not need the value, context or revision parameters at - the end. In this case, it is common to write observer methods that take - only a sender and key value as parameters or, if you aren't interested in - any of these values, to write an observer that has no parameters at all. - - @method addObserver - @param {String} key The key to observer - @param {Object} target The target object to invoke - @param {String|Function} method The method to invoke. - */ - addObserver: function(key, target, method) { - addObserver(this, key, target, method); - }, - - /** - Remove an observer you have previously registered on this object. Pass - the same key, target, and method you passed to `addObserver()` and your - target will no longer receive notifications. - - @method removeObserver - @param {String} key The key to observer - @param {Object} target The target object to invoke - @param {String|Function} method The method to invoke. - */ - removeObserver: function(key, target, method) { - removeObserver(this, key, target, method); - }, - - /** - Returns `true` if the object currently has observers registered for a - particular key. You can use this method to potentially defer performing - an expensive action until someone begins observing a particular property - on the object. - - @method hasObserverFor - @param {String} key Key to check - @return {Boolean} - */ - hasObserverFor: function(key) { - return hasListeners(this, key+':change'); - }, - - /** - Retrieves the value of a property, or a default value in the case that the - property returns `undefined`. - - ```javascript - person.getWithDefault('lastName', 'Doe'); - ``` - - @method getWithDefault - @param {String} keyName The name of the property to retrieve - @param {Object} defaultValue The value to return if the property value is undefined - @return {Object} The property value or the defaultValue. - */ - getWithDefault: function(keyName, defaultValue) { - return getWithDefault(this, keyName, defaultValue); - }, - - /** - Set the value of a property to the current value plus some amount. - - ```javascript - person.incrementProperty('age'); - team.incrementProperty('score', 2); - ``` - - @method incrementProperty - @param {String} keyName The name of the property to increment - @param {Number} increment The amount to increment by. Defaults to 1 - @return {Number} The new property value - */ - incrementProperty: function(keyName, increment) { - if (isNone(increment)) { increment = 1; } - Ember.assert("Must pass a numeric value to incrementProperty", (!isNaN(parseFloat(increment)) && isFinite(increment))); - set(this, keyName, (parseFloat(get(this, keyName)) || 0) + increment); - return get(this, keyName); - }, - - /** - Set the value of a property to the current value minus some amount. - - ```javascript - player.decrementProperty('lives'); - orc.decrementProperty('health', 5); - ``` - - @method decrementProperty - @param {String} keyName The name of the property to decrement - @param {Number} decrement The amount to decrement by. Defaults to 1 - @return {Number} The new property value - */ - decrementProperty: function(keyName, decrement) { - if (isNone(decrement)) { decrement = 1; } - Ember.assert("Must pass a numeric value to decrementProperty", (!isNaN(parseFloat(decrement)) && isFinite(decrement))); - set(this, keyName, (get(this, keyName) || 0) - decrement); - return get(this, keyName); - }, - - /** - Set the value of a boolean property to the opposite of its - current value. - - ```javascript - starship.toggleProperty('warpDriveEngaged'); - ``` - - @method toggleProperty - @param {String} keyName The name of the property to toggle - @return {Object} The new property value - */ - toggleProperty: function(keyName) { - set(this, keyName, !get(this, keyName)); - return get(this, keyName); - }, - - /** - Returns the cached value of a computed property, if it exists. - This allows you to inspect the value of a computed property - without accidentally invoking it if it is intended to be - generated lazily. - - @method cacheFor - @param {String} keyName - @return {Object} The cached value of the computed property, if any - */ - cacheFor: function(keyName) { - return cacheFor(this, keyName); - }, - - // intended for debugging purposes - observersForKey: function(keyName) { - return observersFor(this, keyName); - } - }); - }); -enifed("ember-runtime/mixins/promise_proxy", - ["ember-metal/property_get","ember-metal/set_properties","ember-metal/computed","ember-metal/mixin","ember-metal/error","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - var get = __dependency1__.get; - var setProperties = __dependency2__["default"]; - var computed = __dependency3__.computed; - var Mixin = __dependency4__.Mixin; - var EmberError = __dependency5__["default"]; - - var not = computed.not; - var or = computed.or; - - /** - @module ember - @submodule ember-runtime - */ - - function tap(proxy, promise) { - setProperties(proxy, { - isFulfilled: false, - isRejected: false - }); - - return promise.then(function(value) { - setProperties(proxy, { - content: value, - isFulfilled: true - }); - return value; - }, function(reason) { - setProperties(proxy, { - reason: reason, - isRejected: true - }); - throw reason; - }, "Ember: PromiseProxy"); - } - - /** - A low level mixin making ObjectProxy, ObjectController or ArrayController's promise aware. - - ```javascript - var ObjectPromiseController = Ember.ObjectController.extend(Ember.PromiseProxyMixin); - - var controller = ObjectPromiseController.create({ - promise: $.getJSON('/some/remote/data.json') - }); - - controller.then(function(json){ - // the json - }, function(reason) { - // the reason why you have no json - }); - ``` - - the controller has bindable attributes which - track the promises life cycle - - ```javascript - controller.get('isPending') //=> true - controller.get('isSettled') //=> false - controller.get('isRejected') //=> false - controller.get('isFulfilled') //=> false - ``` - - When the the $.getJSON completes, and the promise is fulfilled - with json, the life cycle attributes will update accordingly. - - ```javascript - controller.get('isPending') //=> false - controller.get('isSettled') //=> true - controller.get('isRejected') //=> false - controller.get('isFulfilled') //=> true - ``` - - As the controller is an ObjectController, and the json now its content, - all the json properties will be available directly from the controller. - - ```javascript - // Assuming the following json: - { - firstName: 'Stefan', - lastName: 'Penner' - } - - // both properties will accessible on the controller - controller.get('firstName') //=> 'Stefan' - controller.get('lastName') //=> 'Penner' - ``` - - If the controller is backing a template, the attributes are - bindable from within that template - - ```handlebars - {{#if isPending}} - loading... - {{else}} - firstName: {{firstName}} - lastName: {{lastName}} - {{/if}} - ``` - @class Ember.PromiseProxyMixin - */ - __exports__["default"] = Mixin.create({ - /** - If the proxied promise is rejected this will contain the reason - provided. - - @property reason - @default null - */ - reason: null, - - /** - Once the proxied promise has settled this will become `false`. - - @property isPending - @default true - */ - isPending: not('isSettled').readOnly(), - - /** - Once the proxied promise has settled this will become `true`. - - @property isSettled - @default false - */ - isSettled: or('isRejected', 'isFulfilled').readOnly(), - - /** - Will become `true` if the proxied promise is rejected. - - @property isRejected - @default false - */ - isRejected: false, - - /** - Will become `true` if the proxied promise is fulfilled. - - @property isFulfilled - @default false - */ - isFulfilled: false, - - /** - The promise whose fulfillment value is being proxied by this object. - - This property must be specified upon creation, and should not be - changed once created. - - Example: - - ```javascript - Ember.ObjectController.extend(Ember.PromiseProxyMixin).create({ - promise: - }); - ``` - - @property promise - */ - promise: computed(function(key, promise) { - if (arguments.length === 2) { - return tap(this, promise); - } else { - throw new EmberError("PromiseProxy's promise must be set"); - } - }), - - /** - An alias to the proxied promise's `then`. - - See RSVP.Promise.then. - - @method then - @param {Function} callback - @return {RSVP.Promise} - */ - then: promiseAlias('then'), - - /** - An alias to the proxied promise's `catch`. - - See RSVP.Promise.catch. - - @method catch - @param {Function} callback - @return {RSVP.Promise} - @since 1.3.0 - */ - 'catch': promiseAlias('catch'), - - /** - An alias to the proxied promise's `finally`. - - See RSVP.Promise.finally. - - @method finally - @param {Function} callback - @return {RSVP.Promise} - @since 1.3.0 - */ - 'finally': promiseAlias('finally') - - }); - - function promiseAlias(name) { - return function () { - var promise = get(this, 'promise'); - return promise[name].apply(promise, arguments); - }; - } - }); -enifed("ember-runtime/mixins/sortable", - ["ember-metal/core","ember-metal/property_get","ember-metal/enumerable_utils","ember-metal/mixin","ember-runtime/mixins/mutable_enumerable","ember-runtime/compare","ember-metal/observer","ember-metal/computed","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - var Ember = __dependency1__["default"]; - // Ember.assert, Ember.A - - var get = __dependency2__.get; - var forEach = __dependency3__.forEach; - var Mixin = __dependency4__.Mixin; - var MutableEnumerable = __dependency5__["default"]; - var compare = __dependency6__["default"]; - var addObserver = __dependency7__.addObserver; - var removeObserver = __dependency7__.removeObserver; - var computed = __dependency8__.computed; - var beforeObserver = __dependency4__.beforeObserver; - var observer = __dependency4__.observer; - //ES6TODO: should we access these directly from their package or from how their exposed in ember-metal? - - /** - `Ember.SortableMixin` provides a standard interface for array proxies - to specify a sort order and maintain this sorting when objects are added, - removed, or updated without changing the implicit order of their underlying - model array: - - ```javascript - songs = [ - {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'}, - {trackNumber: 2, title: 'Back in the U.S.S.R.'}, - {trackNumber: 3, title: 'Glass Onion'}, - ]; - - songsController = Ember.ArrayController.create({ - model: songs, - sortProperties: ['trackNumber'], - sortAscending: true - }); - - songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'} - - songsController.addObject({trackNumber: 1, title: 'Dear Prudence'}); - songsController.get('firstObject'); // {trackNumber: 1, title: 'Dear Prudence'} - ``` - - If you add or remove the properties to sort by or change the sort direction the model - sort order will be automatically updated. - - ```javascript - songsController.set('sortProperties', ['title']); - songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'} - - songsController.toggleProperty('sortAscending'); - songsController.get('firstObject'); // {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'} - ``` - - `SortableMixin` works by sorting the `arrangedContent` array, which is the array that - `ArrayProxy` displays. Due to the fact that the underlying 'content' array is not changed, that - array will not display the sorted list: - - ```javascript - songsController.get('content').get('firstObject'); // Returns the unsorted original content - songsController.get('firstObject'); // Returns the sorted content. - ``` - - Although the sorted content can also be accessed through the `arrangedContent` property, - it is preferable to use the proxied class and not the `arrangedContent` array directly. - - @class SortableMixin - @namespace Ember - @uses Ember.MutableEnumerable - */ - __exports__["default"] = Mixin.create(MutableEnumerable, { - - /** - Specifies which properties dictate the `arrangedContent`'s sort order. - - When specifying multiple properties the sorting will use properties - from the `sortProperties` array prioritized from first to last. - - @property {Array} sortProperties - */ - sortProperties: null, - - /** - Specifies the `arrangedContent`'s sort direction. - Sorts the content in ascending order by default. Set to `false` to - use descending order. - - @property {Boolean} sortAscending - @default true - */ - sortAscending: true, - - /** - The function used to compare two values. You can override this if you - want to do custom comparisons. Functions must be of the type expected by - Array#sort, i.e., - - * return 0 if the two parameters are equal, - * return a negative value if the first parameter is smaller than the second or - * return a positive value otherwise: - - ```javascript - function(x, y) { // These are assumed to be integers - if (x === y) - return 0; - return x < y ? -1 : 1; - } - ``` - - @property sortFunction - @type {Function} - @default Ember.compare - */ - sortFunction: compare, - - orderBy: function(item1, item2) { - var result = 0; - var sortProperties = get(this, 'sortProperties'); - var sortAscending = get(this, 'sortAscending'); - var sortFunction = get(this, 'sortFunction'); - - Ember.assert("you need to define `sortProperties`", !!sortProperties); - - forEach(sortProperties, function(propertyName) { - if (result === 0) { - result = sortFunction.call(this, get(item1, propertyName), get(item2, propertyName)); - if ((result !== 0) && !sortAscending) { - result = (-1) * result; - } - } - }, this); - - return result; - }, - - destroy: function() { - var content = get(this, 'content'); - var sortProperties = get(this, 'sortProperties'); - - if (content && sortProperties) { - forEach(content, function(item) { - forEach(sortProperties, function(sortProperty) { - removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); - }, this); - }, this); - } - - return this._super(); - }, - - isSorted: computed.notEmpty('sortProperties'), - - /** - Overrides the default `arrangedContent` from `ArrayProxy` in order to sort by `sortFunction`. - Also sets up observers for each `sortProperty` on each item in the content Array. - - @property arrangedContent - */ - arrangedContent: computed('content', 'sortProperties.@each', function(key, value) { - var content = get(this, 'content'); - var isSorted = get(this, 'isSorted'); - var sortProperties = get(this, 'sortProperties'); - var self = this; - - if (content && isSorted) { - content = content.slice(); - content.sort(function(item1, item2) { - return self.orderBy(item1, item2); - }); - forEach(content, function(item) { - forEach(sortProperties, function(sortProperty) { - addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); - }, this); - }, this); - return Ember.A(content); - } - - return content; - }), - - _contentWillChange: beforeObserver('content', function() { - var content = get(this, 'content'); - var sortProperties = get(this, 'sortProperties'); - - if (content && sortProperties) { - forEach(content, function(item) { - forEach(sortProperties, function(sortProperty) { - removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); - }, this); - }, this); - } - - this._super(); - }), - - sortPropertiesWillChange: beforeObserver('sortProperties', function() { - this._lastSortAscending = undefined; - }), - - sortPropertiesDidChange: observer('sortProperties', function() { - this._lastSortAscending = undefined; - }), - - sortAscendingWillChange: beforeObserver('sortAscending', function() { - this._lastSortAscending = get(this, 'sortAscending'); - }), - - sortAscendingDidChange: observer('sortAscending', function() { - if (this._lastSortAscending !== undefined && get(this, 'sortAscending') !== this._lastSortAscending) { - var arrangedContent = get(this, 'arrangedContent'); - arrangedContent.reverseObjects(); - } - }), - - contentArrayWillChange: function(array, idx, removedCount, addedCount) { - var isSorted = get(this, 'isSorted'); - - if (isSorted) { - var arrangedContent = get(this, 'arrangedContent'); - var removedObjects = array.slice(idx, idx+removedCount); - var sortProperties = get(this, 'sortProperties'); - - forEach(removedObjects, function(item) { - arrangedContent.removeObject(item); - - forEach(sortProperties, function(sortProperty) { - removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); - }, this); - }, this); - } - - return this._super(array, idx, removedCount, addedCount); - }, - - contentArrayDidChange: function(array, idx, removedCount, addedCount) { - var isSorted = get(this, 'isSorted'); - var sortProperties = get(this, 'sortProperties'); - - if (isSorted) { - var addedObjects = array.slice(idx, idx+addedCount); - - forEach(addedObjects, function(item) { - this.insertItemSorted(item); - - forEach(sortProperties, function(sortProperty) { - addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); - }, this); - }, this); - } - - return this._super(array, idx, removedCount, addedCount); - }, - - insertItemSorted: function(item) { - var arrangedContent = get(this, 'arrangedContent'); - var length = get(arrangedContent, 'length'); - - var idx = this._binarySearch(item, 0, length); - arrangedContent.insertAt(idx, item); - }, - - contentItemSortPropertyDidChange: function(item) { - var arrangedContent = get(this, 'arrangedContent'); - var oldIndex = arrangedContent.indexOf(item); - var leftItem = arrangedContent.objectAt(oldIndex - 1); - var rightItem = arrangedContent.objectAt(oldIndex + 1); - var leftResult = leftItem && this.orderBy(item, leftItem); - var rightResult = rightItem && this.orderBy(item, rightItem); - - if (leftResult < 0 || rightResult > 0) { - arrangedContent.removeObject(item); - this.insertItemSorted(item); - } - }, - - _binarySearch: function(item, low, high) { - var mid, midItem, res, arrangedContent; - - if (low === high) { - return low; - } - - arrangedContent = get(this, 'arrangedContent'); - - mid = low + Math.floor((high - low) / 2); - midItem = arrangedContent.objectAt(mid); - - res = this.orderBy(midItem, item); - - if (res < 0) { - return this._binarySearch(item, mid+1, high); - } else if (res > 0) { - return this._binarySearch(item, low, mid); - } - - return mid; - } - }); - }); -enifed("ember-runtime/mixins/target_action_support", - ["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/mixin","ember-metal/computed","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - var Ember = __dependency1__["default"]; - // Ember.lookup, Ember.assert - - var get = __dependency2__.get; - var typeOf = __dependency3__.typeOf; - var Mixin = __dependency4__.Mixin; - var computed = __dependency5__.computed; - - /** - `Ember.TargetActionSupport` is a mixin that can be included in a class - to add a `triggerAction` method with semantics similar to the Handlebars - `{{action}}` helper. In normal Ember usage, the `{{action}}` helper is - usually the best choice. This mixin is most often useful when you are - doing more complex event handling in View objects. - - See also `Ember.ViewTargetActionSupport`, which has - view-aware defaults for target and actionContext. - - @class TargetActionSupport - @namespace Ember - @extends Ember.Mixin - */ - var TargetActionSupport = Mixin.create({ - target: null, - action: null, - actionContext: null, - - targetObject: computed(function() { - var target = get(this, 'target'); - - if (typeOf(target) === "string") { - var value = get(this, target); - if (value === undefined) { value = get(Ember.lookup, target); } - return value; - } else { - return target; - } - }).property('target'), - - actionContextObject: computed(function() { - var actionContext = get(this, 'actionContext'); - - if (typeOf(actionContext) === "string") { - var value = get(this, actionContext); - if (value === undefined) { value = get(Ember.lookup, actionContext); } - return value; - } else { - return actionContext; - } - }).property('actionContext'), - - /** - Send an `action` with an `actionContext` to a `target`. The action, actionContext - and target will be retrieved from properties of the object. For example: - - ```javascript - App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { - target: Ember.computed.alias('controller'), - action: 'save', - actionContext: Ember.computed.alias('context'), - click: function() { - this.triggerAction(); // Sends the `save` action, along with the current context - // to the current controller - } - }); - ``` - - The `target`, `action`, and `actionContext` can be provided as properties of - an optional object argument to `triggerAction` as well. - - ```javascript - App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { - click: function() { - this.triggerAction({ - action: 'save', - target: this.get('controller'), - actionContext: this.get('context') - }); // Sends the `save` action, along with the current context - // to the current controller - } - }); - ``` - - The `actionContext` defaults to the object you are mixing `TargetActionSupport` into. - But `target` and `action` must be specified either as properties or with the argument - to `triggerAction`, or a combination: - - ```javascript - App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { - target: Ember.computed.alias('controller'), - click: function() { - this.triggerAction({ - action: 'save' - }); // Sends the `save` action, along with a reference to `this`, - // to the current controller - } - }); - ``` - - @method triggerAction - @param opts {Hash} (optional, with the optional keys action, target and/or actionContext) - @return {Boolean} true if the action was sent successfully and did not return false - */ - triggerAction: function(opts) { - opts = opts || {}; - var action = opts.action || get(this, 'action'); - var target = opts.target || get(this, 'targetObject'); - var actionContext = opts.actionContext; - - function args(options, actionName) { - var ret = []; - if (actionName) { ret.push(actionName); } - - return ret.concat(options); - } - - if (typeof actionContext === 'undefined') { - actionContext = get(this, 'actionContextObject') || this; - } - - if (target && action) { - var ret; - - if (target.send) { - ret = target.send.apply(target, args(actionContext, action)); - } else { - Ember.assert("The action '" + action + "' did not exist on " + target, typeof target[action] === 'function'); - ret = target[action].apply(target, args(actionContext)); - } - - if (ret !== false) ret = true; - - return ret; - } else { - return false; - } - } - }); - - __exports__["default"] = TargetActionSupport; - }); -enifed("ember-runtime/system/application", - ["ember-runtime/system/namespace","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Namespace = __dependency1__["default"]; - - __exports__["default"] = Namespace.extend(); - }); -enifed("ember-runtime/system/array_proxy", - ["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/property_events","ember-metal/error","ember-runtime/system/object","ember-runtime/mixins/mutable_array","ember-runtime/mixins/enumerable","ember-runtime/system/string","ember-metal/alias","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - var get = __dependency2__.get; - var isArray = __dependency3__.isArray; - var apply = __dependency3__.apply; - var computed = __dependency4__.computed; - var beforeObserver = __dependency5__.beforeObserver; - var observer = __dependency5__.observer; - var beginPropertyChanges = __dependency6__.beginPropertyChanges; - var endPropertyChanges = __dependency6__.endPropertyChanges; - var EmberError = __dependency7__["default"]; - var EmberObject = __dependency8__["default"]; - var MutableArray = __dependency9__["default"]; - var Enumerable = __dependency10__["default"]; - var fmt = __dependency11__.fmt; - var alias = __dependency12__["default"]; - - /** - @module ember - @submodule ember-runtime - */ - - var OUT_OF_RANGE_EXCEPTION = "Index out of range"; - var EMPTY = []; - - function K() { return this; } - - /** - An ArrayProxy wraps any other object that implements `Ember.Array` and/or - `Ember.MutableArray,` forwarding all requests. This makes it very useful for - a number of binding use cases or other cases where being able to swap - out the underlying array is useful. - - A simple example of usage: - - ```javascript - var pets = ['dog', 'cat', 'fish']; - var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) }); - - ap.get('firstObject'); // 'dog' - ap.set('content', ['amoeba', 'paramecium']); - ap.get('firstObject'); // 'amoeba' - ``` - - This class can also be useful as a layer to transform the contents of - an array, as they are accessed. This can be done by overriding - `objectAtContent`: - - ```javascript - var pets = ['dog', 'cat', 'fish']; - var ap = Ember.ArrayProxy.create({ - content: Ember.A(pets), - objectAtContent: function(idx) { - return this.get('content').objectAt(idx).toUpperCase(); - } - }); - - ap.get('firstObject'); // . 'DOG' - ``` - - @class ArrayProxy - @namespace Ember - @extends Ember.Object - @uses Ember.MutableArray - */ - var ArrayProxy = EmberObject.extend(MutableArray, { - - /** - The content array. Must be an object that implements `Ember.Array` and/or - `Ember.MutableArray.` - - @property content - @type Ember.Array - */ - content: null, - - /** - The array that the proxy pretends to be. In the default `ArrayProxy` - implementation, this and `content` are the same. Subclasses of `ArrayProxy` - can override this property to provide things like sorting and filtering. - - @property arrangedContent - */ - arrangedContent: alias('content'), - - /** - Should actually retrieve the object at the specified index from the - content. You can override this method in subclasses to transform the - content item to something new. - - This method will only be called if content is non-`null`. - - @method objectAtContent - @param {Number} idx The index to retrieve. - @return {Object} the value or undefined if none found - */ - objectAtContent: function(idx) { - return get(this, 'arrangedContent').objectAt(idx); - }, - - /** - Should actually replace the specified objects on the content array. - You can override this method in subclasses to transform the content item - into something new. - - This method will only be called if content is non-`null`. - - @method replaceContent - @param {Number} idx The starting index - @param {Number} amt The number of items to remove from the content. - @param {Array} objects Optional array of objects to insert or null if no - objects. - @return {void} - */ - replaceContent: function(idx, amt, objects) { - get(this, 'content').replace(idx, amt, objects); - }, - - /** - Invoked when the content property is about to change. Notifies observers that the - entire array content will change. - - @private - @method _contentWillChange - */ - _contentWillChange: beforeObserver('content', function() { - this._teardownContent(); - }), - - _teardownContent: function() { - var content = get(this, 'content'); - - if (content) { - content.removeArrayObserver(this, { - willChange: 'contentArrayWillChange', - didChange: 'contentArrayDidChange' - }); - } - }, - - /** - Override to implement content array `willChange` observer. - - @method contentArrayWillChange - - @param {Ember.Array} contentArray the content array - @param {Number} start starting index of the change - @param {Number} removeCount count of items removed - @param {Number} addCount count of items added - - */ - contentArrayWillChange: K, - /** - Override to implement content array `didChange` observer. - - @method contentArrayDidChange - - @param {Ember.Array} contentArray the content array - @param {Number} start starting index of the change - @param {Number} removeCount count of items removed - @param {Number} addCount count of items added - */ - contentArrayDidChange: K, - - /** - Invoked when the content property changes. Notifies observers that the - entire array content has changed. - - @private - @method _contentDidChange - */ - _contentDidChange: observer('content', function() { - var content = get(this, 'content'); - - Ember.assert("Can't set ArrayProxy's content to itself", content !== this); - - this._setupContent(); - }), - - _setupContent: function() { - var content = get(this, 'content'); - - if (content) { - Ember.assert(fmt('ArrayProxy expects an Array or ' + - 'Ember.ArrayProxy, but you passed %@', [typeof content]), - isArray(content) || content.isDestroyed); - - content.addArrayObserver(this, { - willChange: 'contentArrayWillChange', - didChange: 'contentArrayDidChange' - }); - } - }, - - _arrangedContentWillChange: beforeObserver('arrangedContent', function() { - var arrangedContent = get(this, 'arrangedContent'); - var len = arrangedContent ? get(arrangedContent, 'length') : 0; - - this.arrangedContentArrayWillChange(this, 0, len, undefined); - this.arrangedContentWillChange(this); - - this._teardownArrangedContent(arrangedContent); - }), - - _arrangedContentDidChange: observer('arrangedContent', function() { - var arrangedContent = get(this, 'arrangedContent'); - var len = arrangedContent ? get(arrangedContent, 'length') : 0; - - Ember.assert("Can't set ArrayProxy's content to itself", arrangedContent !== this); - - this._setupArrangedContent(); - - this.arrangedContentDidChange(this); - this.arrangedContentArrayDidChange(this, 0, undefined, len); - }), - - _setupArrangedContent: function() { - var arrangedContent = get(this, 'arrangedContent'); - - if (arrangedContent) { - Ember.assert(fmt('ArrayProxy expects an Array or ' + - 'Ember.ArrayProxy, but you passed %@', [typeof arrangedContent]), - isArray(arrangedContent) || arrangedContent.isDestroyed); - - arrangedContent.addArrayObserver(this, { - willChange: 'arrangedContentArrayWillChange', - didChange: 'arrangedContentArrayDidChange' - }); - } - }, - - _teardownArrangedContent: function() { - var arrangedContent = get(this, 'arrangedContent'); - - if (arrangedContent) { - arrangedContent.removeArrayObserver(this, { - willChange: 'arrangedContentArrayWillChange', - didChange: 'arrangedContentArrayDidChange' - }); - } - }, - - arrangedContentWillChange: K, - arrangedContentDidChange: K, - - objectAt: function(idx) { - return get(this, 'content') && this.objectAtContent(idx); - }, - - length: computed(function() { - var arrangedContent = get(this, 'arrangedContent'); - return arrangedContent ? get(arrangedContent, 'length') : 0; - // No dependencies since Enumerable notifies length of change - }), - - _replace: function(idx, amt, objects) { - var content = get(this, 'content'); - Ember.assert('The content property of '+ this.constructor + ' should be set before modifying it', content); - if (content) this.replaceContent(idx, amt, objects); - return this; - }, - - replace: function() { - if (get(this, 'arrangedContent') === get(this, 'content')) { - apply(this, this._replace, arguments); - } else { - throw new EmberError("Using replace on an arranged ArrayProxy is not allowed."); - } - }, - - _insertAt: function(idx, object) { - if (idx > get(this, 'content.length')) throw new EmberError(OUT_OF_RANGE_EXCEPTION); - this._replace(idx, 0, [object]); - return this; - }, - - insertAt: function(idx, object) { - if (get(this, 'arrangedContent') === get(this, 'content')) { - return this._insertAt(idx, object); - } else { - throw new EmberError("Using insertAt on an arranged ArrayProxy is not allowed."); - } - }, - - removeAt: function(start, len) { - if ('number' === typeof start) { - var content = get(this, 'content'); - var arrangedContent = get(this, 'arrangedContent'); - var indices = []; - var i; - - if ((start < 0) || (start >= get(this, 'length'))) { - throw new EmberError(OUT_OF_RANGE_EXCEPTION); - } - - if (len === undefined) len = 1; - - // Get a list of indices in original content to remove - for (i=start; i 0 && - indexOf(concatenatedProperties, keyName) >= 0) { - var baseValue = this[keyName]; - - if (baseValue) { - if ('function' === typeof baseValue.concat) { - value = baseValue.concat(value); - } else { - value = makeArray(baseValue).concat(value); - } - } else { - value = makeArray(value); - } - } - - if (mergedProperties && - mergedProperties.length && - indexOf(mergedProperties, keyName) >= 0) { - var originalValue = this[keyName]; - - value = merge(originalValue, value); - } - - if (desc) { - desc.set(this, keyName, value); - } else { - if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { - this.setUnknownProperty(keyName, value); - } else { - - if (hasPropertyAccessors) { - defineProperty(this, keyName, null, value); // setup mandatory setter - } else { - this[keyName] = value; - } - } - } - } - } - } - - finishPartial(this, m); - - var length = arguments.length; - - if (length === 0) { - this.init(); - } else if (length === 1) { - this.init(arguments[0]); - } else { - // v8 bug potentially incorrectly deopts this function: https://code.google.com/p/v8/issues/detail?id=3709 - // we may want to keep this around till this ages out on mobile - var args = new Array(length); - for (var x = 0; x < length; x++) { - args[x] = arguments[x]; - } - this.init.apply(this, args); - } - - m.proto = proto; - finishChains(this); - sendEvent(this, 'init'); - }; - - Class.toString = Mixin.prototype.toString; - Class.willReopen = function() { - if (wasApplied) { - Class.PrototypeMixin = Mixin.create(Class.PrototypeMixin); - } - - wasApplied = false; - }; - Class._initMixins = function(args) { initMixins = args; }; - Class._initProperties = function(args) { initProperties = args; }; - - Class.proto = function() { - var superclass = Class.superclass; - if (superclass) { superclass.proto(); } - - if (!wasApplied) { - wasApplied = true; - Class.PrototypeMixin.applyPartial(Class.prototype); - } - - return this.prototype; - }; - - return Class; - - } - - /** - @class CoreObject - @namespace Ember - */ - var CoreObject = makeCtor(); - CoreObject.toString = function() { return "Ember.CoreObject"; }; - CoreObject.PrototypeMixin = Mixin.create({ - reopen: function() { - var length = arguments.length; - var args = new Array(length); - for (var i = 0; i < length; i++) { - args[i] = arguments[i]; - } - applyMixin(this, args, true); - return this; - }, - - /** - An overridable method called when objects are instantiated. By default, - does nothing unless it is overridden during class definition. - - Example: - - ```javascript - App.Person = Ember.Object.extend({ - init: function() { - alert('Name is ' + this.get('name')); - } - }); - - var steve = App.Person.create({ - name: "Steve" - }); - - // alerts 'Name is Steve'. - ``` - - NOTE: If you do override `init` for a framework class like `Ember.View` or - `Ember.ArrayController`, be sure to call `this._super()` in your - `init` declaration! If you don't, Ember may not have an opportunity to - do important setup work, and you'll see strange behavior in your - application. - - @method init - */ - init: function() {}, - - /** - Defines the properties that will be concatenated from the superclass - (instead of overridden). - - By default, when you extend an Ember class a property defined in - the subclass overrides a property with the same name that is defined - in the superclass. However, there are some cases where it is preferable - to build up a property's value by combining the superclass' property - value with the subclass' value. An example of this in use within Ember - is the `classNames` property of `Ember.View`. - - Here is some sample code showing the difference between a concatenated - property and a normal one: - - ```javascript - App.BarView = Ember.View.extend({ - someNonConcatenatedProperty: ['bar'], - classNames: ['bar'] - }); - - App.FooBarView = App.BarView.extend({ - someNonConcatenatedProperty: ['foo'], - classNames: ['foo'] - }); - - var fooBarView = App.FooBarView.create(); - fooBarView.get('someNonConcatenatedProperty'); // ['foo'] - fooBarView.get('classNames'); // ['ember-view', 'bar', 'foo'] - ``` - - This behavior extends to object creation as well. Continuing the - above example: - - ```javascript - var view = App.FooBarView.create({ - someNonConcatenatedProperty: ['baz'], - classNames: ['baz'] - }) - view.get('someNonConcatenatedProperty'); // ['baz'] - view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] - ``` - Adding a single property that is not an array will just add it in the array: - - ```javascript - var view = App.FooBarView.create({ - classNames: 'baz' - }) - view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] - ``` - - Using the `concatenatedProperties` property, we can tell Ember to mix the - content of the properties. - - In `Ember.View` the `classNameBindings` and `attributeBindings` properties - are also concatenated, in addition to `classNames`. - - This feature is available for you to use throughout the Ember object model, - although typical app developers are likely to use it infrequently. Since - it changes expectations about behavior of properties, you should properly - document its usage in each individual concatenated property (to not - mislead your users to think they can override the property in a subclass). - - @property concatenatedProperties - @type Array - @default null - */ - concatenatedProperties: null, - - /** - Destroyed object property flag. - - if this property is `true` the observers and bindings were already - removed by the effect of calling the `destroy()` method. - - @property isDestroyed - @default false - */ - isDestroyed: false, - - /** - Destruction scheduled flag. The `destroy()` method has been called. - - The object stays intact until the end of the run loop at which point - the `isDestroyed` flag is set. - - @property isDestroying - @default false - */ - isDestroying: false, - - /** - Destroys an object by setting the `isDestroyed` flag and removing its - metadata, which effectively destroys observers and bindings. - - If you try to set a property on a destroyed object, an exception will be - raised. - - Note that destruction is scheduled for the end of the run loop and does not - happen immediately. It will set an isDestroying flag immediately. - - @method destroy - @return {Ember.Object} receiver - */ - destroy: function() { - if (this.isDestroying) { return; } - this.isDestroying = true; - - schedule('actions', this, this.willDestroy); - schedule('destroy', this, this._scheduledDestroy); - return this; - }, - - /** - Override to implement teardown. - - @method willDestroy - */ - willDestroy: K, - - /** - Invoked by the run loop to actually destroy the object. This is - scheduled for execution by the `destroy` method. - - @private - @method _scheduledDestroy - */ - _scheduledDestroy: function() { - if (this.isDestroyed) { return; } - destroy(this); - this.isDestroyed = true; - }, - - bind: function(to, from) { - if (!(from instanceof Binding)) { from = Binding.from(from); } - from.to(to).connect(this); - return from; - }, - - /** - Returns a string representation which attempts to provide more information - than Javascript's `toString` typically does, in a generic way for all Ember - objects. - - ```javascript - App.Person = Em.Object.extend() - person = App.Person.create() - person.toString() //=> "" - ``` - - If the object's class is not defined on an Ember namespace, it will - indicate it is a subclass of the registered superclass: - - ```javascript - Student = App.Person.extend() - student = Student.create() - student.toString() //=> "<(subclass of App.Person):ember1025>" - ``` - - If the method `toStringExtension` is defined, its return value will be - included in the output. - - ```javascript - App.Teacher = App.Person.extend({ - toStringExtension: function() { - return this.get('fullName'); - } - }); - teacher = App.Teacher.create() - teacher.toString(); //=> "" - ``` - - @method toString - @return {String} string representation - */ - toString: function toString() { - var hasToStringExtension = typeof this.toStringExtension === 'function'; - var extension = hasToStringExtension ? ":" + this.toStringExtension() : ''; - var ret = '<'+this.constructor.toString()+':'+guidFor(this)+extension+'>'; - - this.toString = makeToString(ret); - return ret; - } - }); - - CoreObject.PrototypeMixin.ownerConstructor = CoreObject; - - function makeToString(ret) { - return function() { return ret; }; - } - - CoreObject.__super__ = null; - - var ClassMixinProps = { - - ClassMixin: required(), - - PrototypeMixin: required(), - - isClass: true, - - isMethod: false, - - /** - Creates a new subclass. - - ```javascript - App.Person = Ember.Object.extend({ - say: function(thing) { - alert(thing); - } - }); - ``` - - This defines a new subclass of Ember.Object: `App.Person`. It contains one method: `say()`. - - You can also create a subclass from any existing class by calling its `extend()` method. For example, you might want to create a subclass of Ember's built-in `Ember.View` class: - - ```javascript - App.PersonView = Ember.View.extend({ - tagName: 'li', - classNameBindings: ['isAdministrator'] - }); - ``` - - When defining a subclass, you can override methods but still access the implementation of your parent class by calling the special `_super()` method: - - ```javascript - App.Person = Ember.Object.extend({ - say: function(thing) { - var name = this.get('name'); - alert(name + ' says: ' + thing); - } - }); - - App.Soldier = App.Person.extend({ - say: function(thing) { - this._super(thing + ", sir!"); - }, - march: function(numberOfHours) { - alert(this.get('name') + ' marches for ' + numberOfHours + ' hours.') - } - }); - - var yehuda = App.Soldier.create({ - name: "Yehuda Katz" - }); - - yehuda.say("Yes"); // alerts "Yehuda Katz says: Yes, sir!" - ``` - - The `create()` on line #17 creates an *instance* of the `App.Soldier` class. The `extend()` on line #8 creates a *subclass* of `App.Person`. Any instance of the `App.Person` class will *not* have the `march()` method. - - You can also pass `Mixin` classes to add additional properties to the subclass. - - ```javascript - App.Person = Ember.Object.extend({ - say: function(thing) { - alert(this.get('name') + ' says: ' + thing); - } - }); - - App.SingingMixin = Mixin.create({ - sing: function(thing){ - alert(this.get('name') + ' sings: la la la ' + thing); - } - }); - - App.BroadwayStar = App.Person.extend(App.SingingMixin, { - dance: function() { - alert(this.get('name') + ' dances: tap tap tap tap '); - } - }); - ``` - - The `App.BroadwayStar` class contains three methods: `say()`, `sing()`, and `dance()`. - - @method extend - @static - - @param {Mixin} [mixins]* One or more Mixin classes - @param {Object} [arguments]* Object containing values to use within the new class - */ - extend: function extend() { - var Class = makeCtor(); - var proto; - Class.ClassMixin = Mixin.create(this.ClassMixin); - Class.PrototypeMixin = Mixin.create(this.PrototypeMixin); - - Class.ClassMixin.ownerConstructor = Class; - Class.PrototypeMixin.ownerConstructor = Class; - - reopen.apply(Class.PrototypeMixin, arguments); - - Class.superclass = this; - Class.__super__ = this.prototype; - - proto = Class.prototype = o_create(this.prototype); - proto.constructor = Class; - generateGuid(proto); - meta(proto).proto = proto; // this will disable observers on prototype - - Class.ClassMixin.apply(Class); - return Class; - }, - - /** - Equivalent to doing `extend(arguments).create()`. - If possible use the normal `create` method instead. - - @method createWithMixins - @static - @param [arguments]* - */ - createWithMixins: function() { - var C = this; - var l= arguments.length; - if (l > 0) { - var args = new Array(l); - for (var i = 0; i < l; i++) { - args[i] = arguments[i]; - } - this._initMixins(args); - } - return new C(); - }, - - /** - Creates an instance of a class. Accepts either no arguments, or an object - containing values to initialize the newly instantiated object with. - - ```javascript - App.Person = Ember.Object.extend({ - helloWorld: function() { - alert("Hi, my name is " + this.get('name')); - } - }); - - var tom = App.Person.create({ - name: 'Tom Dale' - }); - - tom.helloWorld(); // alerts "Hi, my name is Tom Dale". - ``` - - `create` will call the `init` function if defined during - `Ember.AnyObject.extend` - - If no arguments are passed to `create`, it will not set values to the new - instance during initialization: - - ```javascript - var noName = App.Person.create(); - noName.helloWorld(); // alerts undefined - ``` - - NOTE: For performance reasons, you cannot declare methods or computed - properties during `create`. You should instead declare methods and computed - properties when using `extend` or use the `createWithMixins` shorthand. - - @method create - @static - @param [arguments]* - */ - create: function() { - var C = this; - var l = arguments.length; - if (l > 0) { - var args = new Array(l); - for (var i = 0; i < l; i++) { - args[i] = arguments[i]; - } - this._initProperties(args); - } - return new C(); - }, - - /** - Augments a constructor's prototype with additional - properties and functions: - - ```javascript - MyObject = Ember.Object.extend({ - name: 'an object' - }); - - o = MyObject.create(); - o.get('name'); // 'an object' - - MyObject.reopen({ - say: function(msg){ - console.log(msg); - } - }) - - o2 = MyObject.create(); - o2.say("hello"); // logs "hello" - - o.say("goodbye"); // logs "goodbye" - ``` - - To add functions and properties to the constructor itself, - see `reopenClass` - - @method reopen - */ - reopen: function() { - this.willReopen(); - - var l = arguments.length; - var args = new Array(l); - if (l > 0) { - for (var i = 0; i < l; i++) { - args[i] = arguments[i]; - } - } - - apply(this.PrototypeMixin, reopen, args); - return this; - }, - - /** - Augments a constructor's own properties and functions: - - ```javascript - MyObject = Ember.Object.extend({ - name: 'an object' - }); - - MyObject.reopenClass({ - canBuild: false - }); - - MyObject.canBuild; // false - o = MyObject.create(); - ``` - - In other words, this creates static properties and functions for the class. These are only available on the class - and not on any instance of that class. - - ```javascript - App.Person = Ember.Object.extend({ - name : "", - sayHello : function(){ - alert("Hello. My name is " + this.get('name')); - } - }); - - App.Person.reopenClass({ - species : "Homo sapiens", - createPerson: function(newPersonsName){ - return App.Person.create({ - name:newPersonsName - }); - } - }); - - var tom = App.Person.create({ - name : "Tom Dale" - }); - var yehuda = App.Person.createPerson("Yehuda Katz"); - - tom.sayHello(); // "Hello. My name is Tom Dale" - yehuda.sayHello(); // "Hello. My name is Yehuda Katz" - alert(App.Person.species); // "Homo sapiens" - ``` - - Note that `species` and `createPerson` are *not* valid on the `tom` and `yehuda` - variables. They are only valid on `App.Person`. - - To add functions and properties to instances of - a constructor by extending the constructor's prototype - see `reopen` - - @method reopenClass - */ - reopenClass: function() { - var l = arguments.length; - var args = new Array(l); - if (l > 0) { - for (var i = 0; i < l; i++) { - args[i] = arguments[i]; - } - } - - apply(this.ClassMixin, reopen, args); - applyMixin(this, arguments, false); - return this; - }, - - detect: function(obj) { - if ('function' !== typeof obj) { return false; } - while(obj) { - if (obj===this) { return true; } - obj = obj.superclass; - } - return false; - }, - - detectInstance: function(obj) { - return obj instanceof this; - }, - - /** - In some cases, you may want to annotate computed properties with additional - metadata about how they function or what values they operate on. For - example, computed property functions may close over variables that are then - no longer available for introspection. - - You can pass a hash of these values to a computed property like this: - - ```javascript - person: function() { - var personId = this.get('personId'); - return App.Person.create({ id: personId }); - }.property().meta({ type: App.Person }) - ``` - - Once you've done this, you can retrieve the values saved to the computed - property from your class like this: - - ```javascript - MyClass.metaForProperty('person'); - ``` - - This will return the original hash that was passed to `meta()`. - - @static - @method metaForProperty - @param key {String} property name - */ - metaForProperty: function(key) { - var meta = this.proto()['__ember_meta__']; - var desc = meta && meta.descs[key]; - - Ember.assert("metaForProperty() could not find a computed property with key '"+key+"'.", !!desc && desc instanceof ComputedProperty); - return desc._meta || {}; - }, - - _computedProperties: computed(function() { - hasCachedComputedProperties = true; - var proto = this.proto(); - var descs = meta(proto).descs; - var property; - var properties = []; - - for (var name in descs) { - property = descs[name]; - - if (property instanceof ComputedProperty) { - properties.push({ - name: name, - meta: property._meta - }); - } - } - return properties; - }).readOnly(), - - /** - Iterate over each computed property for the class, passing its name - and any associated metadata (see `metaForProperty`) to the callback. - - @static - @method eachComputedProperty - @param {Function} callback - @param {Object} binding - */ - eachComputedProperty: function(callback, binding) { - var property, name; - var empty = {}; - - var properties = get(this, '_computedProperties'); - - for (var i = 0, length = properties.length; i < length; i++) { - property = properties[i]; - name = property.name; - callback.call(binding || this, property.name, property.meta || empty); - } - } - }; - - function injectedPropertyAssertion() { - Ember.assert("Injected properties are invalid", validatePropertyInjections(this)); - } - - function addOnLookupHandler() { - Ember.runInDebug(function() { - /** - Provides lookup-time type validation for injected properties. - - @private - @method _onLookup - */ - ClassMixinProps._onLookup = injectedPropertyAssertion; - }); - } - - - addOnLookupHandler(); - - /** - Returns a hash of property names and container names that injected - properties will lookup on the container lazily. - - @method _lazyInjections - @return {Object} Hash of all lazy injected property keys to container names - */ - ClassMixinProps._lazyInjections = function() { - var injections = {}; - var proto = this.proto(); - var descs = meta(proto).descs; - var key, desc; - - for (key in descs) { - desc = descs[key]; - if (desc instanceof InjectedProperty) { - injections[key] = desc.type + ':' + (desc.name || key); - } - } - - return injections; - }; - - - var ClassMixin = Mixin.create(ClassMixinProps); - - ClassMixin.ownerConstructor = CoreObject; - - CoreObject.ClassMixin = ClassMixin; - - ClassMixin.apply(CoreObject); - - CoreObject.reopen({ - didDefineProperty: function(proto, key, value) { - if (hasCachedComputedProperties === false) { return; } - if (value instanceof Ember.ComputedProperty) { - var cache = Ember.meta(this.constructor).cache; - - if (cache._computedProperties !== undefined) { - cache._computedProperties = undefined; - } - } - } - }); - - __exports__["default"] = CoreObject; - }); -enifed("ember-runtime/system/deferred", - ["ember-metal/core","ember-runtime/mixins/deferred","ember-runtime/system/object","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var DeferredMixin = __dependency2__["default"]; - var EmberObject = __dependency3__["default"]; - - var Deferred = EmberObject.extend(DeferredMixin, { - init: function() { - Ember.deprecate('Usage of Ember.Deferred is deprecated.', false, { url: 'http://emberjs.com/guides/deprecations/#toc_deprecate-ember-deferredmixin-and-ember-deferred' }); - this._super(); - } - }); - - Deferred.reopenClass({ - promise: function(callback, binding) { - var deferred = Deferred.create(); - callback.call(binding, deferred); - return deferred; - } - }); - - __exports__["default"] = Deferred; - }); -enifed("ember-runtime/system/each_proxy", - ["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/enumerable_utils","ember-metal/array","ember-runtime/mixins/array","ember-runtime/system/object","ember-metal/computed","ember-metal/observer","ember-metal/events","ember-metal/properties","ember-metal/property_events","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - - var get = __dependency2__.get; - var guidFor = __dependency3__.guidFor; - var forEach = __dependency4__.forEach; - var indexOf = __dependency5__.indexOf; - var EmberArray = __dependency6__["default"]; - // ES6TODO: WAT? Circular dep? - var EmberObject = __dependency7__["default"]; - var computed = __dependency8__.computed; - var addObserver = __dependency9__.addObserver; - var addBeforeObserver = __dependency9__.addBeforeObserver; - var removeBeforeObserver = __dependency9__.removeBeforeObserver; - var removeObserver = __dependency9__.removeObserver; - var typeOf = __dependency3__.typeOf; - var watchedEvents = __dependency10__.watchedEvents; - var defineProperty = __dependency11__.defineProperty; - var beginPropertyChanges = __dependency12__.beginPropertyChanges; - var propertyDidChange = __dependency12__.propertyDidChange; - var propertyWillChange = __dependency12__.propertyWillChange; - var endPropertyChanges = __dependency12__.endPropertyChanges; - var changeProperties = __dependency12__.changeProperties; - - var EachArray = EmberObject.extend(EmberArray, { - - init: function(content, keyName, owner) { - this._super(); - this._keyName = keyName; - this._owner = owner; - this._content = content; - }, - - objectAt: function(idx) { - var item = this._content.objectAt(idx); - return item && get(item, this._keyName); - }, - - length: computed(function() { - var content = this._content; - return content ? get(content, 'length') : 0; - }) - - }); - - var IS_OBSERVER = /^.+:(before|change)$/; - - function addObserverForContentKey(content, keyName, proxy, idx, loc) { - var objects = proxy._objects; - var guid; - if (!objects) objects = proxy._objects = {}; - - while(--loc>=idx) { - var item = content.objectAt(loc); - if (item) { - Ember.assert('When using @each to observe the array ' + content + ', the array must return an object', typeOf(item) === 'instance' || typeOf(item) === 'object'); - addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); - addObserver(item, keyName, proxy, 'contentKeyDidChange'); - - // keep track of the index each item was found at so we can map - // it back when the obj changes. - guid = guidFor(item); - if (!objects[guid]) objects[guid] = []; - objects[guid].push(loc); - } - } - } - - function removeObserverForContentKey(content, keyName, proxy, idx, loc) { - var objects = proxy._objects; - if (!objects) objects = proxy._objects = {}; - var indicies, guid; - - while(--loc>=idx) { - var item = content.objectAt(loc); - if (item) { - removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); - removeObserver(item, keyName, proxy, 'contentKeyDidChange'); - - guid = guidFor(item); - indicies = objects[guid]; - indicies[indexOf.call(indicies, loc)] = null; - } - } - } - - /** - This is the object instance returned when you get the `@each` property on an - array. It uses the unknownProperty handler to automatically create - EachArray instances for property names. - - @private - @class EachProxy - @namespace Ember - @extends Ember.Object - */ - var EachProxy = EmberObject.extend({ - - init: function(content) { - this._super(); - this._content = content; - content.addArrayObserver(this); - - // in case someone is already observing some keys make sure they are - // added - forEach(watchedEvents(this), function(eventName) { - this.didAddListener(eventName); - }, this); - }, - - /** - You can directly access mapped properties by simply requesting them. - The `unknownProperty` handler will generate an EachArray of each item. - - @method unknownProperty - @param keyName {String} - @param value {*} - */ - unknownProperty: function(keyName, value) { - var ret; - ret = new EachArray(this._content, keyName, this); - defineProperty(this, keyName, null, ret); - this.beginObservingContentKey(keyName); - return ret; - }, - - // .......................................................... - // ARRAY CHANGES - // Invokes whenever the content array itself changes. - - arrayWillChange: function(content, idx, removedCnt, addedCnt) { - var keys = this._keys; - var key, lim; - - lim = removedCnt>0 ? idx+removedCnt : -1; - beginPropertyChanges(this); - - for(key in keys) { - if (!keys.hasOwnProperty(key)) { continue; } - - if (lim>0) { removeObserverForContentKey(content, key, this, idx, lim); } - - propertyWillChange(this, key); - } - - propertyWillChange(this._content, '@each'); - endPropertyChanges(this); - }, - - arrayDidChange: function(content, idx, removedCnt, addedCnt) { - var keys = this._keys; - var lim; - - lim = addedCnt>0 ? idx+addedCnt : -1; - changeProperties(function() { - for(var key in keys) { - if (!keys.hasOwnProperty(key)) { continue; } - - if (lim>0) { addObserverForContentKey(content, key, this, idx, lim); } - - propertyDidChange(this, key); - } - - propertyDidChange(this._content, '@each'); - }, this); - }, - - // .......................................................... - // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS - // Start monitoring keys based on who is listening... - - didAddListener: function(eventName) { - if (IS_OBSERVER.test(eventName)) { - this.beginObservingContentKey(eventName.slice(0, -7)); - } - }, - - didRemoveListener: function(eventName) { - if (IS_OBSERVER.test(eventName)) { - this.stopObservingContentKey(eventName.slice(0, -7)); - } - }, - - // .......................................................... - // CONTENT KEY OBSERVING - // Actual watch keys on the source content. - - beginObservingContentKey: function(keyName) { - var keys = this._keys; - if (!keys) keys = this._keys = {}; - if (!keys[keyName]) { - keys[keyName] = 1; - var content = this._content; - var len = get(content, 'length'); - - addObserverForContentKey(content, keyName, this, 0, len); - } else { - keys[keyName]++; - } - }, - - stopObservingContentKey: function(keyName) { - var keys = this._keys; - if (keys && (keys[keyName]>0) && (--keys[keyName]<=0)) { - var content = this._content; - var len = get(content, 'length'); - - removeObserverForContentKey(content, keyName, this, 0, len); - } - }, - - contentKeyWillChange: function(obj, keyName) { - propertyWillChange(this, keyName); - }, - - contentKeyDidChange: function(obj, keyName) { - propertyDidChange(this, keyName); - } - }); - - __exports__.EachArray = EachArray; - __exports__.EachProxy = EachProxy; - }); -enifed("ember-runtime/system/lazy_load", - ["ember-metal/core","ember-metal/array","ember-runtime/system/native_array","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - /*globals CustomEvent */ - - var Ember = __dependency1__["default"]; - // Ember.ENV.EMBER_LOAD_HOOKS - var forEach = __dependency2__.forEach; - // make sure Ember.A is setup. - - /** - @module ember - @submodule ember-runtime - */ - - var loadHooks = Ember.ENV.EMBER_LOAD_HOOKS || {}; - var loaded = {}; - - /** - Detects when a specific package of Ember (e.g. 'Ember.Handlebars') - has fully loaded and is available for extension. - - The provided `callback` will be called with the `name` passed - resolved from a string into the object: - - ``` javascript - Ember.onLoad('Ember.Handlebars' function(hbars) { - hbars.registerHelper(...); - }); - ``` - - @method onLoad - @for Ember - @param name {String} name of hook - @param callback {Function} callback to be called - */ - function onLoad(name, callback) { - var object; - - loadHooks[name] = loadHooks[name] || Ember.A(); - loadHooks[name].pushObject(callback); - - if (object = loaded[name]) { - callback(object); - } - } - - __exports__.onLoad = onLoad;/** - Called when an Ember.js package (e.g Ember.Handlebars) has finished - loading. Triggers any callbacks registered for this event. - - @method runLoadHooks - @for Ember - @param name {String} name of hook - @param object {Object} object to pass to callbacks - */ - function runLoadHooks(name, object) { - loaded[name] = object; - - if (typeof window === 'object' && typeof window.dispatchEvent === 'function' && typeof CustomEvent === "function") { - var event = new CustomEvent(name, {detail: object, name: name}); - window.dispatchEvent(event); - } - - if (loadHooks[name]) { - forEach.call(loadHooks[name], function(callback) { - callback(object); - }); - } - } - - __exports__.runLoadHooks = runLoadHooks; - }); -enifed("ember-runtime/system/namespace", - ["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/mixin","ember-runtime/system/object","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - // Ember.lookup, Ember.BOOTED, Ember.deprecate, Ember.NAME_KEY, Ember.anyUnprocessedMixins - var Ember = __dependency1__["default"]; - var get = __dependency2__.get; - var indexOf = __dependency3__.indexOf; - var GUID_KEY = __dependency4__.GUID_KEY; - var guidFor = __dependency4__.guidFor; - var Mixin = __dependency5__.Mixin; - - var EmberObject = __dependency6__["default"]; - - /** - A Namespace is an object usually used to contain other objects or methods - such as an application or framework. Create a namespace anytime you want - to define one of these new containers. - - # Example Usage - - ```javascript - MyFramework = Ember.Namespace.create({ - VERSION: '1.0.0' - }); - ``` - - @class Namespace - @namespace Ember - @extends Ember.Object - */ - var Namespace = EmberObject.extend({ - isNamespace: true, - - init: function() { - Namespace.NAMESPACES.push(this); - Namespace.PROCESSED = false; - }, - - toString: function() { - var name = get(this, 'name') || get(this, 'modulePrefix'); - if (name) { return name; } - - findNamespaces(); - return this[NAME_KEY]; - }, - - nameClasses: function() { - processNamespace([this.toString()], this, {}); - }, - - destroy: function() { - var namespaces = Namespace.NAMESPACES; - var toString = this.toString(); - - if (toString) { - Ember.lookup[toString] = undefined; - delete Namespace.NAMESPACES_BY_ID[toString]; - } - namespaces.splice(indexOf.call(namespaces, this), 1); - this._super(); - } - }); - - Namespace.reopenClass({ - NAMESPACES: [Ember], - NAMESPACES_BY_ID: {}, - PROCESSED: false, - processAll: processAllNamespaces, - byName: function(name) { - if (!Ember.BOOTED) { - processAllNamespaces(); - } - - return NAMESPACES_BY_ID[name]; - } - }); - - var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID; - - var hasOwnProp = ({}).hasOwnProperty; - - function processNamespace(paths, root, seen) { - var idx = paths.length; - - NAMESPACES_BY_ID[paths.join('.')] = root; - - // Loop over all of the keys in the namespace, looking for classes - for(var key in root) { - if (!hasOwnProp.call(root, key)) { continue; } - var obj = root[key]; - - // If we are processing the `Ember` namespace, for example, the - // `paths` will start with `["Ember"]`. Every iteration through - // the loop will update the **second** element of this list with - // the key, so processing `Ember.View` will make the Array - // `['Ember', 'View']`. - paths[idx] = key; - - // If we have found an unprocessed class - if (obj && obj.toString === classToString) { - // Replace the class' `toString` with the dot-separated path - // and set its `NAME_KEY` - obj.toString = makeToString(paths.join('.')); - obj[NAME_KEY] = paths.join('.'); - - // Support nested namespaces - } else if (obj && obj.isNamespace) { - // Skip aliased namespaces - if (seen[guidFor(obj)]) { continue; } - seen[guidFor(obj)] = true; - - // Process the child namespace - processNamespace(paths, obj, seen); - } - } - - paths.length = idx; // cut out last item - } - - var STARTS_WITH_UPPERCASE = /^[A-Z]/; - - function tryIsNamespace(lookup, prop) { - try { - var obj = lookup[prop]; - return obj && obj.isNamespace && obj; - } catch (e) { - // continue - } - } - - function findNamespaces() { - var lookup = Ember.lookup; - var obj; - - if (Namespace.PROCESSED) { return; } - - for (var prop in lookup) { - // Only process entities that start with uppercase A-Z - if (!STARTS_WITH_UPPERCASE.test(prop)) { continue; } - - // Unfortunately, some versions of IE don't support window.hasOwnProperty - if (lookup.hasOwnProperty && !lookup.hasOwnProperty(prop)) { continue; } - - // At times we are not allowed to access certain properties for security reasons. - // There are also times where even if we can access them, we are not allowed to access their properties. - obj = tryIsNamespace(lookup, prop); - if (obj) { - obj[NAME_KEY] = prop; - } - } - } - - var NAME_KEY = Ember.NAME_KEY = GUID_KEY + '_name'; - - function superClassString(mixin) { - var superclass = mixin.superclass; - if (superclass) { - if (superclass[NAME_KEY]) { return superclass[NAME_KEY]; } - else { return superClassString(superclass); } - } else { - return; - } - } - - function classToString() { - if (!Ember.BOOTED && !this[NAME_KEY]) { - processAllNamespaces(); - } - - var ret; - - if (this[NAME_KEY]) { - ret = this[NAME_KEY]; - } else if (this._toString) { - ret = this._toString; - } else { - var str = superClassString(this); - if (str) { - ret = "(subclass of " + str + ")"; - } else { - ret = "(unknown mixin)"; - } - this.toString = makeToString(ret); - } - - return ret; - } - - function processAllNamespaces() { - var unprocessedNamespaces = !Namespace.PROCESSED; - var unprocessedMixins = Ember.anyUnprocessedMixins; - - if (unprocessedNamespaces) { - findNamespaces(); - Namespace.PROCESSED = true; - } - - if (unprocessedNamespaces || unprocessedMixins) { - var namespaces = Namespace.NAMESPACES; - var namespace; - - for (var i=0, l=namespaces.length; i 0) { - NativeArray = NativeArray.without.apply(NativeArray, ignore); - } - - /** - Creates an `Ember.NativeArray` from an Array like object. - Does not modify the original object. Ember.A is not needed if - `Ember.EXTEND_PROTOTYPES` is `true` (the default value). However, - it is recommended that you use Ember.A when creating addons for - ember or when you can not guarantee that `Ember.EXTEND_PROTOTYPES` - will be `true`. - - Example - - ```js - var Pagination = Ember.CollectionView.extend({ - tagName: 'ul', - classNames: ['pagination'], - - init: function() { - this._super(); - if (!this.get('content')) { - this.set('content', Ember.A()); - } - } - }); - ``` - - @method A - @for Ember - @return {Ember.NativeArray} - */ - var A = function(arr) { - if (arr === undefined) { arr = []; } - return EmberArray.detect(arr) ? arr : NativeArray.apply(arr); - }; - - /** - Activates the mixin on the Array.prototype if not already applied. Calling - this method more than once is safe. This will be called when ember is loaded - unless you have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` - set to `false`. - - Example - - ```js - if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) { - Ember.NativeArray.activate(); - } - ``` - - @method activate - @for Ember.NativeArray - @static - @return {void} - */ - NativeArray.activate = function() { - NativeArray.apply(Array.prototype); - - A = function(arr) { return arr || []; }; - }; - - if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) { - NativeArray.activate(); - } - - Ember.A = A; // ES6TODO: Setting A onto the object returned by ember-metal/core to avoid circles - __exports__.A = A; - __exports__.NativeArray = NativeArray; - __exports__["default"] = NativeArray; - }); -enifed("ember-runtime/system/object", - ["ember-runtime/system/core_object","ember-runtime/mixins/observable","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - var CoreObject = __dependency1__["default"]; - var Observable = __dependency2__["default"]; - - /** - `Ember.Object` is the main base class for all Ember objects. It is a subclass - of `Ember.CoreObject` with the `Ember.Observable` mixin applied. For details, - see the documentation for each of these. - - @class Object - @namespace Ember - @extends Ember.CoreObject - @uses Ember.Observable - */ - var EmberObject = CoreObject.extend(Observable); - EmberObject.toString = function() { - return "Ember.Object"; - }; - - __exports__["default"] = EmberObject; - }); -enifed("ember-runtime/system/object_proxy", - ["ember-runtime/system/object","ember-runtime/mixins/-proxy","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var EmberObject = __dependency1__["default"]; - var _ProxyMixin = __dependency2__["default"]; - - /** - `Ember.ObjectProxy` forwards all properties not defined by the proxy itself - to a proxied `content` object. - - ```javascript - object = Ember.Object.create({ - name: 'Foo' - }); - - proxy = Ember.ObjectProxy.create({ - content: object - }); - - // Access and change existing properties - proxy.get('name') // 'Foo' - proxy.set('name', 'Bar'); - object.get('name') // 'Bar' - - // Create new 'description' property on `object` - proxy.set('description', 'Foo is a whizboo baz'); - object.get('description') // 'Foo is a whizboo baz' - ``` - - While `content` is unset, setting a property to be delegated will throw an - Error. - - ```javascript - proxy = Ember.ObjectProxy.create({ - content: null, - flag: null - }); - proxy.set('flag', true); - proxy.get('flag'); // true - proxy.get('foo'); // undefined - proxy.set('foo', 'data'); // throws Error - ``` - - Delegated properties can be bound to and will change when content is updated. - - Computed properties on the proxy itself can depend on delegated properties. - - ```javascript - ProxyWithComputedProperty = Ember.ObjectProxy.extend({ - fullName: function () { - var firstName = this.get('firstName'), - lastName = this.get('lastName'); - if (firstName && lastName) { - return firstName + ' ' + lastName; - } - return firstName || lastName; - }.property('firstName', 'lastName') - }); - - proxy = ProxyWithComputedProperty.create(); - - proxy.get('fullName'); // undefined - proxy.set('content', { - firstName: 'Tom', lastName: 'Dale' - }); // triggers property change for fullName on proxy - - proxy.get('fullName'); // 'Tom Dale' - ``` - - @class ObjectProxy - @namespace Ember - @extends Ember.Object - @extends Ember._ProxyMixin - */ - - __exports__["default"] = EmberObject.extend(_ProxyMixin); - }); -enifed("ember-runtime/system/service", - ["ember-runtime/system/object","ember-runtime/inject","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Object = __dependency1__["default"]; - var createInjectionHelper = __dependency2__.createInjectionHelper; - - var Service; - - - /** - @class Service - @namespace Ember - @extends Ember.Object - */ - Service = Object.extend(); - - /** - Creates a property that lazily looks up a service in the container. There - are no restrictions as to what objects a service can be injected into. - - Example: - - ```javascript - App.ApplicationRoute = Ember.Route.extend({ - authManager: Ember.inject.service('auth'), - - model: function() { - return this.get('authManager').findCurrentUser(); - } - }); - ``` - - This example will create an `authManager` property on the application route - that looks up the `auth` service in the container, making it easily - accessible in the `model` hook. - - @method inject.service - @for Ember - @param {String} name (optional) name of the service to inject, defaults to - the property's name - @return {Ember.InjectedProperty} injection descriptor instance - */ - createInjectionHelper('service'); - - - __exports__["default"] = Service; - }); -enifed("ember-runtime/system/set", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/is_none","ember-runtime/system/string","ember-runtime/system/core_object","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","ember-runtime/mixins/copyable","ember-runtime/mixins/freezable","ember-metal/error","ember-metal/property_events","ember-metal/mixin","ember-metal/computed","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - var Ember = __dependency1__["default"]; - // Ember.isNone, Ember.A - - var get = __dependency2__.get; - var set = __dependency3__.set; - var guidFor = __dependency4__.guidFor; - var isNone = __dependency5__["default"]; - var fmt = __dependency6__.fmt; - var CoreObject = __dependency7__["default"]; - var MutableEnumerable = __dependency8__["default"]; - var Enumerable = __dependency9__["default"]; - var Copyable = __dependency10__["default"]; - var Freezable = __dependency11__.Freezable; - var FROZEN_ERROR = __dependency11__.FROZEN_ERROR; - var EmberError = __dependency12__["default"]; - var propertyWillChange = __dependency13__.propertyWillChange; - var propertyDidChange = __dependency13__.propertyDidChange; - var aliasMethod = __dependency14__.aliasMethod; - var computed = __dependency15__.computed; - - /** - An unordered collection of objects. - - A Set works a bit like an array except that its items are not ordered. You - can create a set to efficiently test for membership for an object. You can - also iterate through a set just like an array, even accessing objects by - index, however there is no guarantee as to their order. - - All Sets are observable via the Enumerable Observer API - which works - on any enumerable object including both Sets and Arrays. - - ## Creating a Set - - You can create a set like you would most objects using - `new Ember.Set()`. Most new sets you create will be empty, but you can - also initialize the set with some content by passing an array or other - enumerable of objects to the constructor. - - Finally, you can pass in an existing set and the set will be copied. You - can also create a copy of a set by calling `Ember.Set#copy()`. - - ```javascript - // creates a new empty set - var foundNames = new Ember.Set(); - - // creates a set with four names in it. - var names = new Ember.Set(["Charles", "Tom", "Juan", "Alex"]); // :P - - // creates a copy of the names set. - var namesCopy = new Ember.Set(names); - - // same as above. - var anotherNamesCopy = names.copy(); - ``` - - ## Adding/Removing Objects - - You generally add or remove objects from a set using `add()` or - `remove()`. You can add any type of object including primitives such as - numbers, strings, and booleans. - - Unlike arrays, objects can only exist one time in a set. If you call `add()` - on a set with the same object multiple times, the object will only be added - once. Likewise, calling `remove()` with the same object multiple times will - remove the object the first time and have no effect on future calls until - you add the object to the set again. - - NOTE: You cannot add/remove `null` or `undefined` to a set. Any attempt to do - so will be ignored. - - In addition to add/remove you can also call `push()`/`pop()`. Push behaves - just like `add()` but `pop()`, unlike `remove()` will pick an arbitrary - object, remove it and return it. This is a good way to use a set as a job - queue when you don't care which order the jobs are executed in. - - ## Testing for an Object - - To test for an object's presence in a set you simply call - `Ember.Set#contains()`. - - ## Observing changes - - When using `Ember.Set`, you can observe the `"[]"` property to be - alerted whenever the content changes. You can also add an enumerable - observer to the set to be notified of specific objects that are added and - removed from the set. See [Ember.Enumerable](/api/classes/Ember.Enumerable.html) - for more information on enumerables. - - This is often unhelpful. If you are filtering sets of objects, for instance, - it is very inefficient to re-filter all of the items each time the set - changes. It would be better if you could just adjust the filtered set based - on what was changed on the original set. The same issue applies to merging - sets, as well. - - ## Other Methods - - `Ember.Set` primary implements other mixin APIs. For a complete reference - on the methods you will use with `Ember.Set`, please consult these mixins. - The most useful ones will be `Ember.Enumerable` and - `Ember.MutableEnumerable` which implement most of the common iterator - methods you are used to on Array. - - Note that you can also use the `Ember.Copyable` and `Ember.Freezable` - APIs on `Ember.Set` as well. Once a set is frozen it can no longer be - modified. The benefit of this is that when you call `frozenCopy()` on it, - Ember will avoid making copies of the set. This allows you to write - code that can know with certainty when the underlying set data will or - will not be modified. - - @class Set - @namespace Ember - @extends Ember.CoreObject - @uses Ember.MutableEnumerable - @uses Ember.Copyable - @uses Ember.Freezable - @since Ember 0.9 - @deprecated - */ - __exports__["default"] = CoreObject.extend(MutableEnumerable, Copyable, Freezable, { - - // .......................................................... - // IMPLEMENT ENUMERABLE APIS - // - - /** - This property will change as the number of objects in the set changes. - - @property length - @type number - @default 0 - */ - length: 0, - - /** - Clears the set. This is useful if you want to reuse an existing set - without having to recreate it. - - ```javascript - var colors = new Ember.Set(["red", "green", "blue"]); - colors.length; // 3 - colors.clear(); - colors.length; // 0 - ``` - - @method clear - @return {Ember.Set} An empty Set - */ - clear: function() { - if (this.isFrozen) { throw new EmberError(FROZEN_ERROR); } - - var len = get(this, 'length'); - if (len === 0) { return this; } - - var guid; - - this.enumerableContentWillChange(len, 0); - propertyWillChange(this, 'firstObject'); - propertyWillChange(this, 'lastObject'); - - for (var i=0; i < len; i++) { - guid = guidFor(this[i]); - delete this[guid]; - delete this[i]; - } - - set(this, 'length', 0); - - propertyDidChange(this, 'firstObject'); - propertyDidChange(this, 'lastObject'); - this.enumerableContentDidChange(len, 0); - - return this; - }, - - /** - Returns true if the passed object is also an enumerable that contains the - same objects as the receiver. - - ```javascript - var colors = ["red", "green", "blue"], - same_colors = new Ember.Set(colors); - - same_colors.isEqual(colors); // true - same_colors.isEqual(["purple", "brown"]); // false - ``` - - @method isEqual - @param {Ember.Set} obj the other object. - @return {Boolean} - */ - isEqual: function(obj) { - // fail fast - if (!Enumerable.detect(obj)) return false; - - var loc = get(this, 'length'); - if (get(obj, 'length') !== loc) return false; - - while(--loc >= 0) { - if (!obj.contains(this[loc])) return false; - } - - return true; - }, - - /** - Adds an object to the set. Only non-`null` objects can be added to a set - and those can only be added once. If the object is already in the set or - the passed value is null this method will have no effect. - - This is an alias for `Ember.MutableEnumerable.addObject()`. - - ```javascript - var colors = new Ember.Set(); - colors.add("blue"); // ["blue"] - colors.add("blue"); // ["blue"] - colors.add("red"); // ["blue", "red"] - colors.add(null); // ["blue", "red"] - colors.add(undefined); // ["blue", "red"] - ``` - - @method add - @param {Object} obj The object to add. - @return {Ember.Set} The set itself. - */ - add: aliasMethod('addObject'), - - /** - Removes the object from the set if it is found. If you pass a `null` value - or an object that is already not in the set, this method will have no - effect. This is an alias for `Ember.MutableEnumerable.removeObject()`. - - ```javascript - var colors = new Ember.Set(["red", "green", "blue"]); - colors.remove("red"); // ["blue", "green"] - colors.remove("purple"); // ["blue", "green"] - colors.remove(null); // ["blue", "green"] - ``` - - @method remove - @param {Object} obj The object to remove - @return {Ember.Set} The set itself. - */ - remove: aliasMethod('removeObject'), - - /** - Removes the last element from the set and returns it, or `null` if it's empty. - - ```javascript - var colors = new Ember.Set(["green", "blue"]); - colors.pop(); // "blue" - colors.pop(); // "green" - colors.pop(); // null - ``` - - @method pop - @return {Object} The removed object from the set or null. - */ - pop: function() { - if (get(this, 'isFrozen')) throw new EmberError(FROZEN_ERROR); - var obj = this.length > 0 ? this[this.length-1] : null; - this.remove(obj); - return obj; - }, - - /** - Inserts the given object on to the end of the set. It returns - the set itself. - - This is an alias for `Ember.MutableEnumerable.addObject()`. - - ```javascript - var colors = new Ember.Set(); - colors.push("red"); // ["red"] - colors.push("green"); // ["red", "green"] - colors.push("blue"); // ["red", "green", "blue"] - ``` - - @method push - @return {Ember.Set} The set itself. - */ - push: aliasMethod('addObject'), - - /** - Removes the last element from the set and returns it, or `null` if it's empty. - - This is an alias for `Ember.Set.pop()`. - - ```javascript - var colors = new Ember.Set(["green", "blue"]); - colors.shift(); // "blue" - colors.shift(); // "green" - colors.shift(); // null - ``` - - @method shift - @return {Object} The removed object from the set or null. - */ - shift: aliasMethod('pop'), - - /** - Inserts the given object on to the end of the set. It returns - the set itself. - - This is an alias of `Ember.Set.push()` - - ```javascript - var colors = new Ember.Set(); - colors.unshift("red"); // ["red"] - colors.unshift("green"); // ["red", "green"] - colors.unshift("blue"); // ["red", "green", "blue"] - ``` - - @method unshift - @return {Ember.Set} The set itself. - */ - unshift: aliasMethod('push'), - - /** - Adds each object in the passed enumerable to the set. - - This is an alias of `Ember.MutableEnumerable.addObjects()` - - ```javascript - var colors = new Ember.Set(); - colors.addEach(["red", "green", "blue"]); // ["red", "green", "blue"] - ``` - - @method addEach - @param {Ember.Enumerable} objects the objects to add. - @return {Ember.Set} The set itself. - */ - addEach: aliasMethod('addObjects'), - - /** - Removes each object in the passed enumerable to the set. - - This is an alias of `Ember.MutableEnumerable.removeObjects()` - - ```javascript - var colors = new Ember.Set(["red", "green", "blue"]); - colors.removeEach(["red", "blue"]); // ["green"] - ``` - - @method removeEach - @param {Ember.Enumerable} objects the objects to remove. - @return {Ember.Set} The set itself. - */ - removeEach: aliasMethod('removeObjects'), - - // .......................................................... - // PRIVATE ENUMERABLE SUPPORT - // - - init: function(items) { - Ember.deprecate('Ember.Set is deprecated and will be removed in a future release.'); - this._super(); - if (items) this.addObjects(items); - }, - - // implement Ember.Enumerable - nextObject: function(idx) { - return this[idx]; - }, - - // more optimized version - firstObject: computed(function() { - return this.length > 0 ? this[0] : undefined; - }), - - // more optimized version - lastObject: computed(function() { - return this.length > 0 ? this[this.length-1] : undefined; - }), - - // implements Ember.MutableEnumerable - addObject: function(obj) { - if (get(this, 'isFrozen')) throw new EmberError(FROZEN_ERROR); - if (isNone(obj)) return this; // nothing to do - - var guid = guidFor(obj); - var idx = this[guid]; - var len = get(this, 'length'); - var added; - - if (idx>=0 && idx=0 && idx=0; - }, - - copy: function() { - var C = this.constructor, ret = new C(), loc = get(this, 'length'); - set(ret, 'length', loc); - while(--loc>=0) { - ret[loc] = this[loc]; - ret[guidFor(this[loc])] = loc; - } - return ret; - }, - - toString: function() { - var len = this.length, idx, array = []; - for(idx = 0; idx < len; idx++) { - array[idx] = this[idx]; - } - return fmt("Ember.Set<%@>", [array.join(',')]); - } - }); - }); -enifed("ember-runtime/system/string", - ["ember-metal/core","ember-metal/utils","ember-metal/cache","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - var Ember = __dependency1__["default"]; - // Ember.STRINGS, Ember.FEATURES - var isArray = __dependency2__.isArray; - var emberInspect = __dependency2__.inspect; - - var Cache = __dependency3__["default"]; - - var STRING_DASHERIZE_REGEXP = (/[ _]/g); - - var STRING_DASHERIZE_CACHE = new Cache(1000, function(key) { - return decamelize(key).replace(STRING_DASHERIZE_REGEXP, '-'); - }); - - var CAMELIZE_CACHE = new Cache(1000, function(key) { - return key.replace(STRING_CAMELIZE_REGEXP, function(match, separator, chr) { - return chr ? chr.toUpperCase() : ''; - }).replace(/^([A-Z])/, function(match, separator, chr) { - return match.toLowerCase(); - }); - }); - - var CLASSIFY_CACHE = new Cache(1000, function(str) { - var parts = str.split("."); - var out = []; - - for (var i=0, l=parts.length; i 2) { - cachedFormats = new Array(arguments.length - 1); - - for (var i = 1, l = arguments.length; i < l; i++) { - cachedFormats[i - 1] = arguments[i]; - } - } - - // first, replace any ORDERED replacements. - var idx = 0; // the current index for non-numerical replacements - return str.replace(/%@([0-9]+)?/g, function(s, argIndex) { - argIndex = (argIndex) ? parseInt(argIndex, 10) - 1 : idx++; - s = cachedFormats[argIndex]; - return (s === null) ? '(null)' : (s === undefined) ? '' : emberInspect(s); - }); - } - - function loc(str, formats) { - if (!isArray(formats) || arguments.length > 2) { - formats = Array.prototype.slice.call(arguments, 1); - } - - str = Ember.STRINGS[str] || str; - return fmt(str, formats); - } - - function w(str) { - return str.split(/\s+/); - } - - function decamelize(str) { - return DECAMELIZE_CACHE.get(str); - } - - function dasherize(str) { - return STRING_DASHERIZE_CACHE.get(str); - } - - function camelize(str) { - return CAMELIZE_CACHE.get(str); - } - - function classify(str) { - return CLASSIFY_CACHE.get(str); - } - - function underscore(str) { - return UNDERSCORE_CACHE.get(str); - } - - function capitalize(str) { - return CAPITALIZE_CACHE.get(str); - } - - /** - Defines the hash of localized strings for the current language. Used by - the `Ember.String.loc()` helper. To localize, add string values to this - hash. - - @property STRINGS - @for Ember - @type Hash - */ - Ember.STRINGS = {}; - - /** - Defines string helper methods including string formatting and localization. - Unless `Ember.EXTEND_PROTOTYPES.String` is `false` these methods will also be - added to the `String.prototype` as well. - - @class String - @namespace Ember - @static - */ - __exports__["default"] = { - /** - Apply formatting options to the string. This will look for occurrences - of "%@" in your string and substitute them with the arguments you pass into - this method. If you want to control the specific order of replacement, - you can add a number after the key as well to indicate which argument - you want to insert. - - Ordered insertions are most useful when building loc strings where values - you need to insert may appear in different orders. - - ```javascript - "Hello %@ %@".fmt('John', 'Doe'); // "Hello John Doe" - "Hello %@2, %@1".fmt('John', 'Doe'); // "Hello Doe, John" - ``` - - @method fmt - @param {String} str The string to format - @param {Array} formats An array of parameters to interpolate into string. - @return {String} formatted string - */ - fmt: fmt, - - /** - Formats the passed string, but first looks up the string in the localized - strings hash. This is a convenient way to localize text. See - `Ember.String.fmt()` for more information on formatting. - - Note that it is traditional but not required to prefix localized string - keys with an underscore or other character so you can easily identify - localized strings. - - ```javascript - Ember.STRINGS = { - '_Hello World': 'Bonjour le monde', - '_Hello %@ %@': 'Bonjour %@ %@' - }; - - Ember.String.loc("_Hello World"); // 'Bonjour le monde'; - Ember.String.loc("_Hello %@ %@", ["John", "Smith"]); // "Bonjour John Smith"; - ``` - - @method loc - @param {String} str The string to format - @param {Array} formats Optional array of parameters to interpolate into string. - @return {String} formatted string - */ - loc: loc, - - /** - Splits a string into separate units separated by spaces, eliminating any - empty strings in the process. This is a convenience method for split that - is mostly useful when applied to the `String.prototype`. - - ```javascript - Ember.String.w("alpha beta gamma").forEach(function(key) { - console.log(key); - }); - - // > alpha - // > beta - // > gamma - ``` - - @method w - @param {String} str The string to split - @return {Array} array containing the split strings - */ - w: w, - - /** - Converts a camelized string into all lower case separated by underscores. - - ```javascript - 'innerHTML'.decamelize(); // 'inner_html' - 'action_name'.decamelize(); // 'action_name' - 'css-class-name'.decamelize(); // 'css-class-name' - 'my favorite items'.decamelize(); // 'my favorite items' - ``` - - @method decamelize - @param {String} str The string to decamelize. - @return {String} the decamelized string. - */ - decamelize: decamelize, - - /** - Replaces underscores, spaces, or camelCase with dashes. - - ```javascript - 'innerHTML'.dasherize(); // 'inner-html' - 'action_name'.dasherize(); // 'action-name' - 'css-class-name'.dasherize(); // 'css-class-name' - 'my favorite items'.dasherize(); // 'my-favorite-items' - ``` - - @method dasherize - @param {String} str The string to dasherize. - @return {String} the dasherized string. - */ - dasherize: dasherize, - - /** - Returns the lowerCamelCase form of a string. - - ```javascript - 'innerHTML'.camelize(); // 'innerHTML' - 'action_name'.camelize(); // 'actionName' - 'css-class-name'.camelize(); // 'cssClassName' - 'my favorite items'.camelize(); // 'myFavoriteItems' - 'My Favorite Items'.camelize(); // 'myFavoriteItems' - ``` - - @method camelize - @param {String} str The string to camelize. - @return {String} the camelized string. - */ - camelize: camelize, - - /** - Returns the UpperCamelCase form of a string. - - ```javascript - 'innerHTML'.classify(); // 'InnerHTML' - 'action_name'.classify(); // 'ActionName' - 'css-class-name'.classify(); // 'CssClassName' - 'my favorite items'.classify(); // 'MyFavoriteItems' - ``` - - @method classify - @param {String} str the string to classify - @return {String} the classified string - */ - classify: classify, - - /** - More general than decamelize. Returns the lower\_case\_and\_underscored - form of a string. - - ```javascript - 'innerHTML'.underscore(); // 'inner_html' - 'action_name'.underscore(); // 'action_name' - 'css-class-name'.underscore(); // 'css_class_name' - 'my favorite items'.underscore(); // 'my_favorite_items' - ``` - - @method underscore - @param {String} str The string to underscore. - @return {String} the underscored string. - */ - underscore: underscore, - - /** - Returns the Capitalized form of a string - - ```javascript - 'innerHTML'.capitalize() // 'InnerHTML' - 'action_name'.capitalize() // 'Action_name' - 'css-class-name'.capitalize() // 'Css-class-name' - 'my favorite items'.capitalize() // 'My favorite items' - ``` - - @method capitalize - @param {String} str The string to capitalize. - @return {String} The capitalized string. - */ - capitalize: capitalize - }; - - __exports__.fmt = fmt; - __exports__.loc = loc; - __exports__.w = w; - __exports__.decamelize = decamelize; - __exports__.dasherize = dasherize; - __exports__.camelize = camelize; - __exports__.classify = classify; - __exports__.underscore = underscore; - __exports__.capitalize = capitalize; - }); -enifed("ember-runtime/system/subarray", - ["ember-metal/error","ember-metal/enumerable_utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var EmberError = __dependency1__["default"]; - var EnumerableUtils = __dependency2__["default"]; - - var RETAIN = 'r'; - var FILTER = 'f'; - - function Operation(type, count) { - this.type = type; - this.count = count; - } - - __exports__["default"] = SubArray; - - /** - An `Ember.SubArray` tracks an array in a way similar to, but more specialized - than, `Ember.TrackedArray`. It is useful for keeping track of the indexes of - items within a filtered array. - - @class SubArray - @namespace Ember - */ - function SubArray (length) { - if (arguments.length < 1) { length = 0; } - - if (length > 0) { - this._operations = [new Operation(RETAIN, length)]; - } else { - this._operations = []; - } - } - - - SubArray.prototype = { - /** - Track that an item was added to the tracked array. - - @method addItem - - @param {Number} index The index of the item in the tracked array. - @param {Boolean} match `true` iff the item is included in the subarray. - - @return {number} The index of the item in the subarray. - */ - addItem: function(index, match) { - var returnValue = -1; - var itemType = match ? RETAIN : FILTER; - var self = this; - - this._findOperation(index, function(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) { - var newOperation, splitOperation; - - if (itemType === operation.type) { - ++operation.count; - } else if (index === rangeStart) { - // insert to the left of `operation` - self._operations.splice(operationIndex, 0, new Operation(itemType, 1)); - } else { - newOperation = new Operation(itemType, 1); - splitOperation = new Operation(operation.type, rangeEnd - index + 1); - operation.count = index - rangeStart; - - self._operations.splice(operationIndex + 1, 0, newOperation, splitOperation); - } - - if (match) { - if (operation.type === RETAIN) { - returnValue = seenInSubArray + (index - rangeStart); - } else { - returnValue = seenInSubArray; - } - } - - self._composeAt(operationIndex); - }, function(seenInSubArray) { - self._operations.push(new Operation(itemType, 1)); - - if (match) { - returnValue = seenInSubArray; - } - - self._composeAt(self._operations.length-1); - }); - - return returnValue; - }, - - /** - Track that an item was removed from the tracked array. - - @method removeItem - - @param {Number} index The index of the item in the tracked array. - - @return {number} The index of the item in the subarray, or `-1` if the item - was not in the subarray. - */ - removeItem: function(index) { - var returnValue = -1; - var self = this; - - this._findOperation(index, function (operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) { - if (operation.type === RETAIN) { - returnValue = seenInSubArray + (index - rangeStart); - } - - if (operation.count > 1) { - --operation.count; - } else { - self._operations.splice(operationIndex, 1); - self._composeAt(operationIndex); - } - }, function() { - throw new EmberError("Can't remove an item that has never been added."); - }); - - return returnValue; - }, - - - _findOperation: function (index, foundCallback, notFoundCallback) { - var seenInSubArray = 0; - var operationIndex, len, operation, rangeStart, rangeEnd; - - // OPTIMIZE: change to balanced tree - // find leftmost operation to the right of `index` - for (operationIndex = rangeStart = 0, len = this._operations.length; operationIndex < len; rangeStart = rangeEnd + 1, ++operationIndex) { - operation = this._operations[operationIndex]; - rangeEnd = rangeStart + operation.count - 1; - - if (index >= rangeStart && index <= rangeEnd) { - foundCallback(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray); - return; - } else if (operation.type === RETAIN) { - seenInSubArray += operation.count; - } - } - - notFoundCallback(seenInSubArray); - }, - - _composeAt: function(index) { - var op = this._operations[index]; - var otherOp; - - if (!op) { - // Composing out of bounds is a no-op, as when removing the last operation - // in the list. - return; - } - - if (index > 0) { - otherOp = this._operations[index-1]; - if (otherOp.type === op.type) { - op.count += otherOp.count; - this._operations.splice(index-1, 1); - --index; - } - } - - if (index < this._operations.length-1) { - otherOp = this._operations[index+1]; - if (otherOp.type === op.type) { - op.count += otherOp.count; - this._operations.splice(index+1, 1); - } - } - }, - - toString: function () { - var str = ""; - EnumerableUtils.forEach(this._operations, function (operation) { - str += " " + operation.type + ":" + operation.count; - }); - return str.substring(1); - } - }; - }); -enifed("ember-runtime/system/tracked_array", - ["ember-metal/property_get","ember-metal/enumerable_utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var get = __dependency1__.get; - var forEach = __dependency2__.forEach; - - var RETAIN = 'r'; - var INSERT = 'i'; - var DELETE = 'd'; - - __exports__["default"] = TrackedArray; - - /** - An `Ember.TrackedArray` tracks array operations. It's useful when you want to - lazily compute the indexes of items in an array after they've been shifted by - subsequent operations. - - @class TrackedArray - @namespace Ember - @param {Array} [items=[]] The array to be tracked. This is used just to get - the initial items for the starting state of retain:n. - */ - function TrackedArray(items) { - if (arguments.length < 1) { items = []; } - - var length = get(items, 'length'); - - if (length) { - this._operations = [new ArrayOperation(RETAIN, length, items)]; - } else { - this._operations = []; - } - } - - TrackedArray.RETAIN = RETAIN; - TrackedArray.INSERT = INSERT; - TrackedArray.DELETE = DELETE; - - TrackedArray.prototype = { - - /** - Track that `newItems` were added to the tracked array at `index`. - - @method addItems - @param index - @param newItems - */ - addItems: function (index, newItems) { - var count = get(newItems, 'length'); - if (count < 1) { return; } - - var match = this._findArrayOperation(index); - var arrayOperation = match.operation; - var arrayOperationIndex = match.index; - var arrayOperationRangeStart = match.rangeStart; - var composeIndex, newArrayOperation; - - newArrayOperation = new ArrayOperation(INSERT, count, newItems); - - if (arrayOperation) { - if (!match.split) { - // insert left of arrayOperation - this._operations.splice(arrayOperationIndex, 0, newArrayOperation); - composeIndex = arrayOperationIndex; - } else { - this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); - composeIndex = arrayOperationIndex + 1; - } - } else { - // insert at end - this._operations.push(newArrayOperation); - composeIndex = arrayOperationIndex; - } - - this._composeInsert(composeIndex); - }, - - /** - Track that `count` items were removed at `index`. - - @method removeItems - @param index - @param count - */ - removeItems: function (index, count) { - if (count < 1) { return; } - - var match = this._findArrayOperation(index); - var arrayOperationIndex = match.index; - var arrayOperationRangeStart = match.rangeStart; - var newArrayOperation, composeIndex; - - newArrayOperation = new ArrayOperation(DELETE, count); - if (!match.split) { - // insert left of arrayOperation - this._operations.splice(arrayOperationIndex, 0, newArrayOperation); - composeIndex = arrayOperationIndex; - } else { - this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); - composeIndex = arrayOperationIndex + 1; - } - - return this._composeDelete(composeIndex); - }, - - /** - Apply all operations, reducing them to retain:n, for `n`, the number of - items in the array. - - `callback` will be called for each operation and will be passed the following arguments: - - * {array} items The items for the given operation - * {number} offset The computed offset of the items, ie the index in the - array of the first item for this operation. - * {string} operation The type of the operation. One of - `Ember.TrackedArray.{RETAIN, DELETE, INSERT}` - - @method apply - @param {Function} callback - */ - apply: function (callback) { - var items = []; - var offset = 0; - - forEach(this._operations, function (arrayOperation, operationIndex) { - callback(arrayOperation.items, offset, arrayOperation.type, operationIndex); - - if (arrayOperation.type !== DELETE) { - offset += arrayOperation.count; - items = items.concat(arrayOperation.items); - } - }); - - this._operations = [new ArrayOperation(RETAIN, items.length, items)]; - }, - - /** - Return an `ArrayOperationMatch` for the operation that contains the item at `index`. - - @method _findArrayOperation - - @param {Number} index the index of the item whose operation information - should be returned. - @private - */ - _findArrayOperation: function (index) { - var split = false; - var arrayOperationIndex, arrayOperation, - arrayOperationRangeStart, arrayOperationRangeEnd, - len; - - // OPTIMIZE: we could search these faster if we kept a balanced tree. - // find leftmost arrayOperation to the right of `index` - for (arrayOperationIndex = arrayOperationRangeStart = 0, len = this._operations.length; arrayOperationIndex < len; ++arrayOperationIndex) { - arrayOperation = this._operations[arrayOperationIndex]; - - if (arrayOperation.type === DELETE) { continue; } - - arrayOperationRangeEnd = arrayOperationRangeStart + arrayOperation.count - 1; - - if (index === arrayOperationRangeStart) { - break; - } else if (index > arrayOperationRangeStart && index <= arrayOperationRangeEnd) { - split = true; - break; - } else { - arrayOperationRangeStart = arrayOperationRangeEnd + 1; - } - } - - return new ArrayOperationMatch(arrayOperation, arrayOperationIndex, split, arrayOperationRangeStart); - }, - - _split: function (arrayOperationIndex, splitIndex, newArrayOperation) { - var arrayOperation = this._operations[arrayOperationIndex]; - var splitItems = arrayOperation.items.slice(splitIndex); - var splitArrayOperation = new ArrayOperation(arrayOperation.type, splitItems.length, splitItems); - - // truncate LHS - arrayOperation.count = splitIndex; - arrayOperation.items = arrayOperation.items.slice(0, splitIndex); - - this._operations.splice(arrayOperationIndex + 1, 0, newArrayOperation, splitArrayOperation); - }, - - // see SubArray for a better implementation. - _composeInsert: function (index) { - var newArrayOperation = this._operations[index]; - var leftArrayOperation = this._operations[index-1]; // may be undefined - var rightArrayOperation = this._operations[index+1]; // may be undefined - var leftOp = leftArrayOperation && leftArrayOperation.type; - var rightOp = rightArrayOperation && rightArrayOperation.type; - - if (leftOp === INSERT) { - // merge left - leftArrayOperation.count += newArrayOperation.count; - leftArrayOperation.items = leftArrayOperation.items.concat(newArrayOperation.items); - - if (rightOp === INSERT) { - // also merge right (we have split an insert with an insert) - leftArrayOperation.count += rightArrayOperation.count; - leftArrayOperation.items = leftArrayOperation.items.concat(rightArrayOperation.items); - this._operations.splice(index, 2); - } else { - // only merge left - this._operations.splice(index, 1); - } - } else if (rightOp === INSERT) { - // merge right - newArrayOperation.count += rightArrayOperation.count; - newArrayOperation.items = newArrayOperation.items.concat(rightArrayOperation.items); - this._operations.splice(index + 1, 1); - } - }, - - _composeDelete: function (index) { - var arrayOperation = this._operations[index]; - var deletesToGo = arrayOperation.count; - var leftArrayOperation = this._operations[index-1]; // may be undefined - var leftOp = leftArrayOperation && leftArrayOperation.type; - var nextArrayOperation; - var nextOp; - var nextCount; - var removeNewAndNextOp = false; - var removedItems = []; - - if (leftOp === DELETE) { - arrayOperation = leftArrayOperation; - index -= 1; - } - - for (var i = index + 1; deletesToGo > 0; ++i) { - nextArrayOperation = this._operations[i]; - nextOp = nextArrayOperation.type; - nextCount = nextArrayOperation.count; - - if (nextOp === DELETE) { - arrayOperation.count += nextCount; - continue; - } - - if (nextCount > deletesToGo) { - // d:2 {r,i}:5 we reduce the retain or insert, but it stays - removedItems = removedItems.concat(nextArrayOperation.items.splice(0, deletesToGo)); - nextArrayOperation.count -= deletesToGo; - - // In the case where we truncate the last arrayOperation, we don't need to - // remove it; also the deletesToGo reduction is not the entirety of - // nextCount - i -= 1; - nextCount = deletesToGo; - - deletesToGo = 0; - } else { - if (nextCount === deletesToGo) { - // Handle edge case of d:2 i:2 in which case both operations go away - // during composition. - removeNewAndNextOp = true; - } - removedItems = removedItems.concat(nextArrayOperation.items); - deletesToGo -= nextCount; - } - - if (nextOp === INSERT) { - // d:2 i:3 will result in delete going away - arrayOperation.count -= nextCount; - } - } - - if (arrayOperation.count > 0) { - // compose our new delete with possibly several operations to the right of - // disparate types - this._operations.splice(index+1, i-1-index); - } else { - // The delete operation can go away; it has merely reduced some other - // operation, as in d:3 i:4; it may also have eliminated that operation, - // as in d:3 i:3. - this._operations.splice(index, removeNewAndNextOp ? 2 : 1); - } - - return removedItems; - }, - - toString: function () { - var str = ""; - forEach(this._operations, function (operation) { - str += " " + operation.type + ":" + operation.count; - }); - return str.substring(1); - } - }; - - /** - Internal data structure to represent an array operation. - - @method ArrayOperation - @private - @param {String} type The type of the operation. One of - `Ember.TrackedArray.{RETAIN, INSERT, DELETE}` - @param {Number} count The number of items in this operation. - @param {Array} items The items of the operation, if included. RETAIN and - INSERT include their items, DELETE does not. - */ - function ArrayOperation (operation, count, items) { - this.type = operation; // RETAIN | INSERT | DELETE - this.count = count; - this.items = items; - } - - /** - Internal data structure used to include information when looking up operations - by item index. - - @method ArrayOperationMatch - @private - @param {ArrayOperation} operation - @param {Number} index The index of `operation` in the array of operations. - @param {Boolean} split Whether or not the item index searched for would - require a split for a new operation type. - @param {Number} rangeStart The index of the first item in the operation, - with respect to the tracked array. The index of the last item can be computed - from `rangeStart` and `operation.count`. - */ - function ArrayOperationMatch(operation, index, split, rangeStart) { - this.operation = operation; - this.index = index; - this.split = split; - this.rangeStart = rangeStart; - } - }); -enifed("ember-template-compiler", - ["ember-metal/core","ember-template-compiler/system/precompile","ember-template-compiler/system/compile","ember-template-compiler/system/template","ember-template-compiler/plugins","ember-template-compiler/plugins/transform-each-in-to-hash","ember-template-compiler/plugins/transform-with-as-to-hash","ember-template-compiler/compat","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - var _Ember = __dependency1__["default"]; - var precompile = __dependency2__["default"]; - var compile = __dependency3__["default"]; - var template = __dependency4__["default"]; - var registerPlugin = __dependency5__.registerPlugin; - - var TransformEachInToHash = __dependency6__["default"]; - var TransformWithAsToHash = __dependency7__["default"]; - - // used for adding Ember.Handlebars.compile for backwards compat - - registerPlugin('ast', TransformWithAsToHash); - registerPlugin('ast', TransformEachInToHash); - - __exports__._Ember = _Ember; - __exports__.precompile = precompile; - __exports__.compile = compile; - __exports__.template = template; - __exports__.registerPlugin = registerPlugin; - }); -enifed("ember-template-compiler/compat", - ["ember-metal/core","ember-template-compiler/compat/precompile","ember-template-compiler/system/compile","ember-template-compiler/system/template"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__) { - "use strict"; - var Ember = __dependency1__["default"]; - var precompile = __dependency2__["default"]; - var compile = __dependency3__["default"]; - var template = __dependency4__["default"]; - - var EmberHandlebars = Ember.Handlebars = Ember.Handlebars || {}; - - EmberHandlebars.precompile = precompile; - EmberHandlebars.compile = compile; - EmberHandlebars.template = template; - }); -enifed("ember-template-compiler/compat/precompile", - ["exports"], - function(__exports__) { - "use strict"; - /** - @module ember - @submodule ember-template-compiler - */ - - var compile, compileSpec; - - __exports__["default"] = function(string) { - if ((!compile || !compileSpec) && Ember.__loader.registry['htmlbars-compiler/compiler']) { - var Compiler = requireModule('htmlbars-compiler/compiler'); - - compile = Compiler.compile; - compileSpec = Compiler.compileSpec; - } - - if (!compile || !compileSpec) { - throw new Error('Cannot call `precompile` without the template compiler loaded. Please load `ember-template-compiler.js` prior to calling `precompile`.'); - } - - var asObject = arguments[1] === undefined ? true : arguments[1]; - var compileFunc = asObject ? compile : compileSpec; - - return compileFunc(string); - } - }); -enifed("ember-template-compiler/plugins", - ["exports"], - function(__exports__) { - "use strict"; - /** - @module ember - @submodule ember-template-compiler - */ - - /** - @private - @property helpers - */ - var plugins = { - ast: [ ] - }; - - /** - Adds an AST plugin to be used by Ember.HTMLBars.compile. - - @private - @method registerASTPlugin - */ - function registerPlugin(type, Plugin) { - if (!plugins[type]) { - throw new Error('Attempting to register "' + Plugin + '" as "' + type + '" which is not a valid HTMLBars plugin type.'); - } - - plugins[type].push(Plugin); - } - - __exports__.registerPlugin = registerPlugin;__exports__["default"] = plugins; - }); -enifed("ember-template-compiler/plugins/transform-each-in-to-hash", - ["exports"], - function(__exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - - /** - An HTMLBars AST transformation that replaces all instances of - - ```handlebars - {{#each item in items}} - {{/each}} - ``` - - with - - ```handlebars - {{#each items keyword="item"}} - {{/each}} - ``` - - @class TransformEachInToHash - @private - */ - function TransformEachInToHash() { - // set later within HTMLBars to the syntax package - this.syntax = null; - } - - /** - @private - @method transform - @param {AST} The AST to be transformed. - */ - TransformEachInToHash.prototype.transform = function TransformEachInToHash_transform(ast) { - var pluginContext = this; - var walker = new pluginContext.syntax.Walker(); - var b = pluginContext.syntax.builders; - - walker.visit(ast, function(node) { - if (pluginContext.validate(node)) { - - if (node.program && node.program.blockParams.length) { - throw new Error('You cannot use keyword (`{{each foo in bar}}`) and block params (`{{each bar as |foo|}}`) at the same time.'); - } - - var removedParams = node.sexpr.params.splice(0, 2); - var keyword = removedParams[0].original; - - // TODO: This may not be necessary. - if (!node.sexpr.hash) { - node.sexpr.hash = b.hash(); - } - - node.sexpr.hash.pairs.push(b.pair( - 'keyword', - b.string(keyword) - )); - } - }); - - return ast; - }; - - TransformEachInToHash.prototype.validate = function TransformEachInToHash_validate(node) { - return (node.type === 'BlockStatement' || node.type === 'MustacheStatement') && - node.sexpr.path.original === 'each' && - node.sexpr.params.length === 3 && - node.sexpr.params[1].type === 'PathExpression' && - node.sexpr.params[1].original === 'in'; - }; - - __exports__["default"] = TransformEachInToHash; - }); -enifed("ember-template-compiler/plugins/transform-with-as-to-hash", - ["exports"], - function(__exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - /** - An HTMLBars AST transformation that replaces all instances of - - ```handlebars - {{#with foo.bar as bar}} - {{/with}} - ``` - - with - - ```handlebars - {{#with foo.bar as |bar|}} - {{/with}} - ``` - - @private - @class TransformWithAsToHash - */ - function TransformWithAsToHash() { - // set later within HTMLBars to the syntax package - this.syntax = null; - } - - /** - @private - @method transform - @param {AST} The AST to be transformed. - */ - TransformWithAsToHash.prototype.transform = function TransformWithAsToHash_transform(ast) { - var pluginContext = this; - var walker = new pluginContext.syntax.Walker(); - - walker.visit(ast, function(node) { - if (pluginContext.validate(node)) { - - if (node.program && node.program.blockParams.length) { - throw new Error('You cannot use keyword (`{{with foo as bar}}`) and block params (`{{with foo as |bar|}}`) at the same time.'); - } - - var removedParams = node.sexpr.params.splice(1, 2); - var keyword = removedParams[1].original; - node.program.blockParams = [ keyword ]; - } - }); - - return ast; - }; - - TransformWithAsToHash.prototype.validate = function TransformWithAsToHash_validate(node) { - return node.type === 'BlockStatement' && - node.sexpr.path.original === 'with' && - node.sexpr.params.length === 3 && - node.sexpr.params[1].type === 'PathExpression' && - node.sexpr.params[1].original === 'as'; - }; - - __exports__["default"] = TransformWithAsToHash; - }); -enifed("ember-template-compiler/system/compile", - ["ember-template-compiler/system/compile_options","ember-template-compiler/system/template","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-template-compiler - */ - - var compile; - var compileOptions = __dependency1__["default"]; - var template = __dependency2__["default"]; - - /** - Uses HTMLBars `compile` function to process a string into a compiled template. - - This is not present in production builds. - - @private - @method compile - @param {String} templateString This is the string to be compiled by HTMLBars. - */ - __exports__["default"] = function(templateString) { - if (!compile && Ember.__loader.registry['htmlbars-compiler/compiler']) { - compile = requireModule('htmlbars-compiler/compiler').compile; - } - - if (!compile) { - throw new Error('Cannot call `compile` without the template compiler loaded. Please load `ember-template-compiler.js` prior to calling `compile`.'); - } - - var templateSpec = compile(templateString, compileOptions()); - - return template(templateSpec); - } - }); -enifed("ember-template-compiler/system/compile_options", - ["ember-metal/core","ember-template-compiler/plugins","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-template-compiler - */ - - var Ember = __dependency1__["default"]; - var plugins = __dependency2__["default"]; - - /** - @private - @property compileOptions - */ - __exports__["default"] = function() { - var disableComponentGeneration = true; - - return { - disableComponentGeneration: disableComponentGeneration, - - plugins: plugins - }; - } - }); -enifed("ember-template-compiler/system/precompile", - ["ember-template-compiler/system/compile_options","exports"], - function(__dependency1__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-template-compiler - */ - - var compileOptions = __dependency1__["default"]; - var compileSpec; - - /** - Uses HTMLBars `compile` function to process a string into a compiled template string. - The returned string must be passed through `Ember.HTMLBars.template`. - - This is not present in production builds. - - @private - @method precompile - @param {String} templateString This is the string to be compiled by HTMLBars. - */ - __exports__["default"] = function(templateString) { - if (!compileSpec && Ember.__loader.registry['htmlbars-compiler/compiler']) { - compileSpec = requireModule('htmlbars-compiler/compiler').compileSpec; - } - - if (!compileSpec) { - throw new Error('Cannot call `compileSpec` without the template compiler loaded. Please load `ember-template-compiler.js` prior to calling `compileSpec`.'); - } - - return compileSpec(templateString, compileOptions()); - } - }); -enifed("ember-template-compiler/system/template", - ["exports"], - function(__exports__) { - "use strict"; - /** - @module ember - @submodule ember-template-compiler - */ - - /** - Augments the detault precompiled output of an HTMLBars template with - additional information needed by Ember. - - @private - @method template - @param {Function} templateSpec This is the compiled HTMLBars template spec. - */ - - __exports__["default"] = function(templateSpec) { - templateSpec.isTop = true; - templateSpec.isMethod = false; - - return templateSpec; - } - }); -enifed("ember-testing", - ["ember-metal/core","ember-testing/initializers","ember-testing/support","ember-testing/setup_for_testing","ember-testing/test","ember-testing/adapters/adapter","ember-testing/adapters/qunit","ember-testing/helpers"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) { - "use strict"; - var Ember = __dependency1__["default"]; - - // to setup initializer - // to handle various edge cases - - var setupForTesting = __dependency4__["default"]; - var Test = __dependency5__["default"]; - var Adapter = __dependency6__["default"]; - var QUnitAdapter = __dependency7__["default"]; - // adds helpers to helpers object in Test - - /** - Ember Testing - - @module ember - @submodule ember-testing - @requires ember-application - */ - - Ember.Test = Test; - Ember.Test.Adapter = Adapter; - Ember.Test.QUnitAdapter = QUnitAdapter; - Ember.setupForTesting = setupForTesting; - }); -enifed("ember-testing/adapters/adapter", - ["ember-runtime/system/object","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var EmberObject = __dependency1__["default"]; - - function K() { return this; } - - /** - @module ember - @submodule ember-testing - */ - - /** - The primary purpose of this class is to create hooks that can be implemented - by an adapter for various test frameworks. - - @class Adapter - @namespace Ember.Test - */ - var Adapter = EmberObject.extend({ - /** - This callback will be called whenever an async operation is about to start. - - Override this to call your framework's methods that handle async - operations. - - @public - @method asyncStart - */ - asyncStart: K, - - /** - This callback will be called whenever an async operation has completed. - - @public - @method asyncEnd - */ - asyncEnd: K, - - /** - Override this method with your testing framework's false assertion. - This function is called whenever an exception occurs causing the testing - promise to fail. - - QUnit example: - - ```javascript - exception: function(error) { - ok(false, error); - }; - ``` - - @public - @method exception - @param {String} error The exception to be raised. - */ - exception: function(error) { - throw error; - } - }); - - __exports__["default"] = Adapter; - }); -enifed("ember-testing/adapters/qunit", - ["ember-testing/adapters/adapter","ember-metal/utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Adapter = __dependency1__["default"]; - var inspect = __dependency2__.inspect; - - /** - This class implements the methods defined by Ember.Test.Adapter for the - QUnit testing framework. - - @class QUnitAdapter - @namespace Ember.Test - @extends Ember.Test.Adapter - */ - __exports__["default"] = Adapter.extend({ - asyncStart: function() { - QUnit.stop(); - }, - asyncEnd: function() { - QUnit.start(); - }, - exception: function(error) { - ok(false, inspect(error)); - } - }); - }); -enifed("ember-testing/helpers", - ["ember-metal/property_get","ember-metal/error","ember-metal/run_loop","ember-views/system/jquery","ember-testing/test"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) { - "use strict"; - var get = __dependency1__.get; - var EmberError = __dependency2__["default"]; - var run = __dependency3__["default"]; - var jQuery = __dependency4__["default"]; - var Test = __dependency5__["default"]; - - /** - * @module ember - * @submodule ember-testing - */ - - var helper = Test.registerHelper; - var asyncHelper = Test.registerAsyncHelper; - var countAsync = 0; - - function currentRouteName(app){ - var appController = app.__container__.lookup('controller:application'); - - return get(appController, 'currentRouteName'); - } - - function currentPath(app){ - var appController = app.__container__.lookup('controller:application'); - - return get(appController, 'currentPath'); - } - - function currentURL(app){ - var router = app.__container__.lookup('router:main'); - - return get(router, 'location').getURL(); - } - - function pauseTest(){ - Test.adapter.asyncStart(); - return new Ember.RSVP.Promise(function(){ }, 'TestAdapter paused promise'); - } - - function visit(app, url) { - var router = app.__container__.lookup('router:main'); - router.location.setURL(url); - - if (app._readinessDeferrals > 0) { - router['initialURL'] = url; - run(app, 'advanceReadiness'); - delete router['initialURL']; - } else { - run(app, app.handleURL, url); - } - - return app.testHelpers.wait(); - } - - function click(app, selector, context) { - var $el = app.testHelpers.findWithAssert(selector, context); - run($el, 'mousedown'); - - if ($el.is(':input, [contenteditable=true]')) { - var type = $el.prop('type'); - if (type !== 'checkbox' && type !== 'radio' && type !== 'hidden') { - run($el, function(){ - // Firefox does not trigger the `focusin` event if the window - // does not have focus. If the document doesn't have focus just - // use trigger('focusin') instead. - if (!document.hasFocus || document.hasFocus()) { - this.focus(); - } else { - this.trigger('focusin'); - } - }); - } - } - - run($el, 'mouseup'); - run($el, 'click'); - - return app.testHelpers.wait(); - } - - function triggerEvent(app, selector, contextOrType, typeOrOptions, possibleOptions){ - var arity = arguments.length; - var context, type, options; - - if (arity === 3) { - // context and options are optional, so this is - // app, selector, type - context = null; - type = contextOrType; - options = {}; - } else if (arity === 4) { - // context and options are optional, so this is - if (typeof typeOrOptions === "object") { // either - // app, selector, type, options - context = null; - type = contextOrType; - options = typeOrOptions; - } else { // or - // app, selector, context, type - context = contextOrType; - type = typeOrOptions; - options = {}; - } - } else { - context = contextOrType; - type = typeOrOptions; - options = possibleOptions; - } - - var $el = app.testHelpers.findWithAssert(selector, context); - - var event = jQuery.Event(type, options); - - run($el, 'trigger', event); - - return app.testHelpers.wait(); - } - - function keyEvent(app, selector, contextOrType, typeOrKeyCode, keyCode) { - var context, type; - - if (typeof keyCode === 'undefined') { - context = null; - keyCode = typeOrKeyCode; - type = contextOrType; - } else { - context = contextOrType; - type = typeOrKeyCode; - } - - return app.testHelpers.triggerEvent(selector, context, type, { keyCode: keyCode, which: keyCode }); - } - - function fillIn(app, selector, contextOrText, text) { - var $el, context; - if (typeof text === 'undefined') { - text = contextOrText; - } else { - context = contextOrText; - } - $el = app.testHelpers.findWithAssert(selector, context); - run(function() { - $el.val(text).change(); - }); - return app.testHelpers.wait(); - } - - function findWithAssert(app, selector, context) { - var $el = app.testHelpers.find(selector, context); - if ($el.length === 0) { - throw new EmberError("Element " + selector + " not found."); - } - return $el; - } - - function find(app, selector, context) { - var $el; - context = context || get(app, 'rootElement'); - $el = app.$(selector, context); - - return $el; - } - - function andThen(app, callback) { - return app.testHelpers.wait(callback(app)); - } - - function wait(app, value) { - return Test.promise(function(resolve) { - // If this is the first async promise, kick off the async test - if (++countAsync === 1) { - Test.adapter.asyncStart(); - } - - // Every 10ms, poll for the async thing to have finished - var watcher = setInterval(function() { - var router = app.__container__.lookup('router:main'); - - // 1. If the router is loading, keep polling - var routerIsLoading = router.router && !!router.router.activeTransition; - if (routerIsLoading) { return; } - - // 2. If there are pending Ajax requests, keep polling - if (Test.pendingAjaxRequests) { return; } - - // 3. If there are scheduled timers or we are inside of a run loop, keep polling - if (run.hasScheduledTimers() || run.currentRunLoop) { return; } - if (Test.waiters && Test.waiters.any(function(waiter) { - var context = waiter[0]; - var callback = waiter[1]; - return !callback.call(context); - })) { return; } - // Stop polling - clearInterval(watcher); - - // If this is the last async promise, end the async test - if (--countAsync === 0) { - Test.adapter.asyncEnd(); - } - - // Synchronously resolve the promise - run(null, resolve, value); - }, 10); - }); - - } - - - /** - * Loads a route, sets up any controllers, and renders any templates associated - * with the route as though a real user had triggered the route change while - * using your app. - * - * Example: - * - * ```javascript - * visit('posts/index').then(function() { - * // assert something - * }); - * ``` - * - * @method visit - * @param {String} url the name of the route - * @return {RSVP.Promise} - */ - asyncHelper('visit', visit); - - /** - * Clicks an element and triggers any actions triggered by the element's `click` - * event. - * - * Example: - * - * ```javascript - * click('.some-jQuery-selector').then(function() { - * // assert something - * }); - * ``` - * - * @method click - * @param {String} selector jQuery selector for finding element on the DOM - * @return {RSVP.Promise} - */ - asyncHelper('click', click); - - /** - * Simulates a key event, e.g. `keypress`, `keydown`, `keyup` with the desired keyCode - * - * Example: - * - * ```javascript - * keyEvent('.some-jQuery-selector', 'keypress', 13).then(function() { - * // assert something - * }); - * ``` - * - * @method keyEvent - * @param {String} selector jQuery selector for finding element on the DOM - * @param {String} type the type of key event, e.g. `keypress`, `keydown`, `keyup` - * @param {Number} keyCode the keyCode of the simulated key event - * @return {RSVP.Promise} - * @since 1.5.0 - */ - asyncHelper('keyEvent', keyEvent); - - /** - * Fills in an input element with some text. - * - * Example: - * - * ```javascript - * fillIn('#email', 'you@example.com').then(function() { - * // assert something - * }); - * ``` - * - * @method fillIn - * @param {String} selector jQuery selector finding an input element on the DOM - * to fill text with - * @param {String} text text to place inside the input element - * @return {RSVP.Promise} - */ - asyncHelper('fillIn', fillIn); - - /** - * Finds an element in the context of the app's container element. A simple alias - * for `app.$(selector)`. - * - * Example: - * - * ```javascript - * var $el = find('.my-selector'); - * ``` - * - * @method find - * @param {String} selector jQuery string selector for element lookup - * @return {Object} jQuery object representing the results of the query - */ - helper('find', find); - - /** - * Like `find`, but throws an error if the element selector returns no results. - * - * Example: - * - * ```javascript - * var $el = findWithAssert('.doesnt-exist'); // throws error - * ``` - * - * @method findWithAssert - * @param {String} selector jQuery selector string for finding an element within - * the DOM - * @return {Object} jQuery object representing the results of the query - * @throws {Error} throws error if jQuery object returned has a length of 0 - */ - helper('findWithAssert', findWithAssert); - - /** - Causes the run loop to process any pending events. This is used to ensure that - any async operations from other helpers (or your assertions) have been processed. - - This is most often used as the return value for the helper functions (see 'click', - 'fillIn','visit',etc). - - Example: - - ```javascript - Ember.Test.registerAsyncHelper('loginUser', function(app, username, password) { - visit('secured/path/here') - .fillIn('#username', username) - .fillIn('#password', password) - .click('.submit') - - return app.testHelpers.wait(); - }); - - @method wait - @param {Object} value The value to be returned. - @return {RSVP.Promise} - */ - asyncHelper('wait', wait); - asyncHelper('andThen', andThen); - - - /** - Returns the currently active route name. - - Example: - - ```javascript - function validateRouteName(){ - equal(currentRouteName(), 'some.path', "correct route was transitioned into."); - } - - visit('/some/path').then(validateRouteName) - ``` - - @method currentRouteName - @return {Object} The name of the currently active route. - @since 1.5.0 - */ - helper('currentRouteName', currentRouteName); - - /** - Returns the current path. - - Example: - - ```javascript - function validateURL(){ - equal(currentPath(), 'some.path.index', "correct path was transitioned into."); - } - - click('#some-link-id').then(validateURL); - ``` - - @method currentPath - @return {Object} The currently active path. - @since 1.5.0 - */ - helper('currentPath', currentPath); - - /** - Returns the current URL. - - Example: - - ```javascript - function validateURL(){ - equal(currentURL(), '/some/path', "correct URL was transitioned into."); - } - - click('#some-link-id').then(validateURL); - ``` - - @method currentURL - @return {Object} The currently active URL. - @since 1.5.0 - */ - helper('currentURL', currentURL); - - - /** - Pauses the current test - this is useful for debugging while testing or for test-driving. - It allows you to inspect the state of your application at any point. - - Example (The test will pause before clicking the button): - - ```javascript - visit('/') - return pauseTest(); - - click('.btn'); - ``` - - @since 1.9.0 - @method pauseTest - @return {Object} A promise that will never resolve - */ - helper('pauseTest', pauseTest); - - - /** - Triggers the given DOM event on the element identified by the provided selector. - - Example: - - ```javascript - triggerEvent('#some-elem-id', 'blur'); - ``` - - This is actually used internally by the `keyEvent` helper like so: - - ```javascript - triggerEvent('#some-elem-id', 'keypress', { keyCode: 13 }); - ``` - - @method triggerEvent - @param {String} selector jQuery selector for finding element on the DOM - @param {String} [context] jQuery selector that will limit the selector - argument to find only within the context's children - @param {String} type The event type to be triggered. - @param {Object} [options] The options to be passed to jQuery.Event. - @return {RSVP.Promise} - @since 1.5.0 - */ - asyncHelper('triggerEvent', triggerEvent); - }); -enifed("ember-testing/initializers", - ["ember-runtime/system/lazy_load"], - function(__dependency1__) { - "use strict"; - var onLoad = __dependency1__.onLoad; - - var name = 'deferReadiness in `testing` mode'; - - onLoad('Ember.Application', function(Application) { - if (!Application.initializers[name]) { - Application.initializer({ - name: name, - - initialize: function(container, application){ - if (application.testing) { - application.deferReadiness(); - } - } - }); - } - }); - }); -enifed("ember-testing/setup_for_testing", - ["ember-metal/core","ember-testing/adapters/qunit","ember-views/system/jquery","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // import Test from "ember-testing/test"; // ES6TODO: fix when cycles are supported - var QUnitAdapter = __dependency2__["default"]; - var jQuery = __dependency3__["default"]; - - var Test, requests; - - function incrementAjaxPendingRequests(_, xhr){ - requests.push(xhr); - Test.pendingAjaxRequests = requests.length; - } - - function decrementAjaxPendingRequests(_, xhr){ - for (var i=0;i') - .css({ position: 'absolute', left: '-1000px', top: '-1000px' }) - .appendTo('body') - .on('click', handler) - .trigger('click') - .remove(); - } - - $(function() { - /* - Determine whether a checkbox checked using jQuery's "click" method will have - the correct value for its checked property. - - If we determine that the current jQuery version exhibits this behavior, - patch it to work correctly as in the commit for the actual fix: - https://github.com/jquery/jquery/commit/1fb2f92. - */ - testCheckboxClick(function() { - if (!this.checked && !$.event.special.click) { - $.event.special.click = { - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ($.nodeName( this, "input" ) && this.type === "checkbox" && this.click) { - this.click(); - return false; - } - } - }; - } - }); - - // Try again to verify that the patch took effect or blow up. - testCheckboxClick(function() { - Ember.warn("clicked checkboxes should be checked! the jQuery patch didn't work", this.checked); - }); - }); - }); -enifed("ember-testing/test", - ["ember-metal/core","ember-metal/run_loop","ember-metal/platform","ember-runtime/ext/rsvp","ember-testing/setup_for_testing","ember-application/system/application","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var emberRun = __dependency2__["default"]; - var create = __dependency3__.create; - var RSVP = __dependency4__["default"]; - var setupForTesting = __dependency5__["default"]; - var EmberApplication = __dependency6__["default"]; - - /** - @module ember - @submodule ember-testing - */ - var slice = [].slice; - var helpers = {}; - var injectHelpersCallbacks = []; - - /** - This is a container for an assortment of testing related functionality: - - * Choose your default test adapter (for your framework of choice). - * Register/Unregister additional test helpers. - * Setup callbacks to be fired when the test helpers are injected into - your application. - - @class Test - @namespace Ember - */ - var Test = { - /** - Hash containing all known test helpers. - - @property _helpers - @private - @since 1.7.0 - */ - _helpers: helpers, - - /** - `registerHelper` is used to register a test helper that will be injected - when `App.injectTestHelpers` is called. - - The helper method will always be called with the current Application as - the first parameter. - - For example: - - ```javascript - Ember.Test.registerHelper('boot', function(app) { - Ember.run(app, app.advanceReadiness); - }); - ``` - - This helper can later be called without arguments because it will be - called with `app` as the first parameter. - - ```javascript - App = Ember.Application.create(); - App.injectTestHelpers(); - boot(); - ``` - - @public - @method registerHelper - @param {String} name The name of the helper method to add. - @param {Function} helperMethod - @param options {Object} - */ - registerHelper: function(name, helperMethod) { - helpers[name] = { - method: helperMethod, - meta: { wait: false } - }; - }, - - /** - `registerAsyncHelper` is used to register an async test helper that will be injected - when `App.injectTestHelpers` is called. - - The helper method will always be called with the current Application as - the first parameter. - - For example: - - ```javascript - Ember.Test.registerAsyncHelper('boot', function(app) { - Ember.run(app, app.advanceReadiness); - }); - ``` - - The advantage of an async helper is that it will not run - until the last async helper has completed. All async helpers - after it will wait for it complete before running. - - - For example: - - ```javascript - Ember.Test.registerAsyncHelper('deletePost', function(app, postId) { - click('.delete-' + postId); - }); - - // ... in your test - visit('/post/2'); - deletePost(2); - visit('/post/3'); - deletePost(3); - ``` - - @public - @method registerAsyncHelper - @param {String} name The name of the helper method to add. - @param {Function} helperMethod - @since 1.2.0 - */ - registerAsyncHelper: function(name, helperMethod) { - helpers[name] = { - method: helperMethod, - meta: { wait: true } - }; - }, - - /** - Remove a previously added helper method. - - Example: - - ```javascript - Ember.Test.unregisterHelper('wait'); - ``` - - @public - @method unregisterHelper - @param {String} name The helper to remove. - */ - unregisterHelper: function(name) { - delete helpers[name]; - delete Test.Promise.prototype[name]; - }, - - /** - Used to register callbacks to be fired whenever `App.injectTestHelpers` - is called. - - The callback will receive the current application as an argument. - - Example: - - ```javascript - Ember.Test.onInjectHelpers(function() { - Ember.$(document).ajaxSend(function() { - Test.pendingAjaxRequests++; - }); - - Ember.$(document).ajaxComplete(function() { - Test.pendingAjaxRequests--; - }); - }); - ``` - - @public - @method onInjectHelpers - @param {Function} callback The function to be called. - */ - onInjectHelpers: function(callback) { - injectHelpersCallbacks.push(callback); - }, - - /** - This returns a thenable tailored for testing. It catches failed - `onSuccess` callbacks and invokes the `Ember.Test.adapter.exception` - callback in the last chained then. - - This method should be returned by async helpers such as `wait`. - - @public - @method promise - @param {Function} resolver The function used to resolve the promise. - */ - promise: function(resolver) { - return new Test.Promise(resolver); - }, - - /** - Used to allow ember-testing to communicate with a specific testing - framework. - - You can manually set it before calling `App.setupForTesting()`. - - Example: - - ```javascript - Ember.Test.adapter = MyCustomAdapter.create() - ``` - - If you do not set it, ember-testing will default to `Ember.Test.QUnitAdapter`. - - @public - @property adapter - @type {Class} The adapter to be used. - @default Ember.Test.QUnitAdapter - */ - adapter: null, - - /** - Replacement for `Ember.RSVP.resolve` - The only difference is this uses - an instance of `Ember.Test.Promise` - - @public - @method resolve - @param {Mixed} The value to resolve - @since 1.2.0 - */ - resolve: function(val) { - return Test.promise(function(resolve) { - return resolve(val); - }); - }, - - /** - This allows ember-testing to play nicely with other asynchronous - events, such as an application that is waiting for a CSS3 - transition or an IndexDB transaction. - - For example: - - ```javascript - Ember.Test.registerWaiter(function() { - return myPendingTransactions() == 0; - }); - ``` - The `context` argument allows you to optionally specify the `this` - with which your callback will be invoked. - - For example: - - ```javascript - Ember.Test.registerWaiter(MyDB, MyDB.hasPendingTransactions); - ``` - - @public - @method registerWaiter - @param {Object} context (optional) - @param {Function} callback - @since 1.2.0 - */ - registerWaiter: function(context, callback) { - if (arguments.length === 1) { - callback = context; - context = null; - } - if (!this.waiters) { - this.waiters = Ember.A(); - } - this.waiters.push([context, callback]); - }, - /** - `unregisterWaiter` is used to unregister a callback that was - registered with `registerWaiter`. - - @public - @method unregisterWaiter - @param {Object} context (optional) - @param {Function} callback - @since 1.2.0 - */ - unregisterWaiter: function(context, callback) { - if (!this.waiters) { return; } - if (arguments.length === 1) { - callback = context; - context = null; - } - this.waiters = Ember.A(this.waiters.filter(function(elt) { - return !(elt[0] === context && elt[1] === callback); - })); - } - }; - - function helper(app, name) { - var fn = helpers[name].method; - var meta = helpers[name].meta; - - return function() { - var args = slice.call(arguments); - var lastPromise = Test.lastPromise; - - args.unshift(app); - - // some helpers are not async and - // need to return a value immediately. - // example: `find` - if (!meta.wait) { - return fn.apply(app, args); - } - - if (!lastPromise) { - // It's the first async helper in current context - lastPromise = fn.apply(app, args); - } else { - // wait for last helper's promise to resolve - // and then execute - run(function() { - lastPromise = Test.resolve(lastPromise).then(function() { - return fn.apply(app, args); - }); - }); - } - - return lastPromise; - }; - } - - function run(fn) { - if (!emberRun.currentRunLoop) { - emberRun(fn); - } else { - fn(); - } - } - - EmberApplication.reopen({ - /** - This property contains the testing helpers for the current application. These - are created once you call `injectTestHelpers` on your `Ember.Application` - instance. The included helpers are also available on the `window` object by - default, but can be used from this object on the individual application also. - - @property testHelpers - @type {Object} - @default {} - */ - testHelpers: {}, - - /** - This property will contain the original methods that were registered - on the `helperContainer` before `injectTestHelpers` is called. - - When `removeTestHelpers` is called, these methods are restored to the - `helperContainer`. - - @property originalMethods - @type {Object} - @default {} - @private - @since 1.3.0 - */ - originalMethods: {}, - - - /** - This property indicates whether or not this application is currently in - testing mode. This is set when `setupForTesting` is called on the current - application. - - @property testing - @type {Boolean} - @default false - @since 1.3.0 - */ - testing: false, - - /** - This hook defers the readiness of the application, so that you can start - the app when your tests are ready to run. It also sets the router's - location to 'none', so that the window's location will not be modified - (preventing both accidental leaking of state between tests and interference - with your testing framework). - - Example: - - ``` - App.setupForTesting(); - ``` - - @method setupForTesting - */ - setupForTesting: function() { - setupForTesting(); - - this.testing = true; - - this.Router.reopen({ - location: 'none' - }); - }, - - /** - This will be used as the container to inject the test helpers into. By - default the helpers are injected into `window`. - - @property helperContainer - @type {Object} The object to be used for test helpers. - @default window - @since 1.2.0 - */ - helperContainer: window, - - /** - This injects the test helpers into the `helperContainer` object. If an object is provided - it will be used as the helperContainer. If `helperContainer` is not set it will default - to `window`. If a function of the same name has already been defined it will be cached - (so that it can be reset if the helper is removed with `unregisterHelper` or - `removeTestHelpers`). - - Any callbacks registered with `onInjectHelpers` will be called once the - helpers have been injected. - - Example: - ``` - App.injectTestHelpers(); - ``` - - @method injectTestHelpers - */ - injectTestHelpers: function(helperContainer) { - if (helperContainer) { this.helperContainer = helperContainer; } - - this.testHelpers = {}; - for (var name in helpers) { - this.originalMethods[name] = this.helperContainer[name]; - this.testHelpers[name] = this.helperContainer[name] = helper(this, name); - protoWrap(Test.Promise.prototype, name, helper(this, name), helpers[name].meta.wait); - } - - for(var i = 0, l = injectHelpersCallbacks.length; i < l; i++) { - injectHelpersCallbacks[i](this); - } - }, - - /** - This removes all helpers that have been registered, and resets and functions - that were overridden by the helpers. - - Example: - - ```javascript - App.removeTestHelpers(); - ``` - - @public - @method removeTestHelpers - */ - removeTestHelpers: function() { - for (var name in helpers) { - this.helperContainer[name] = this.originalMethods[name]; - delete this.testHelpers[name]; - delete this.originalMethods[name]; - } - } - }); - - // This method is no longer needed - // But still here for backwards compatibility - // of helper chaining - function protoWrap(proto, name, callback, isAsync) { - proto[name] = function() { - var args = arguments; - if (isAsync) { - return callback.apply(this, args); - } else { - return this.then(function() { - return callback.apply(this, args); - }); - } - }; - } - - Test.Promise = function() { - RSVP.Promise.apply(this, arguments); - Test.lastPromise = this; - }; - - Test.Promise.prototype = create(RSVP.Promise.prototype); - Test.Promise.prototype.constructor = Test.Promise; - - // Patch `then` to isolate async methods - // specifically `Ember.Test.lastPromise` - var originalThen = RSVP.Promise.prototype.then; - Test.Promise.prototype.then = function(onSuccess, onFailure) { - return originalThen.call(this, function(val) { - return isolate(onSuccess, val); - }, onFailure); - }; - - // This method isolates nested async methods - // so that they don't conflict with other last promises. - // - // 1. Set `Ember.Test.lastPromise` to null - // 2. Invoke method - // 3. Return the last promise created during method - // 4. Restore `Ember.Test.lastPromise` to original value - function isolate(fn, val) { - var value, lastPromise; - - // Reset lastPromise for nested helpers - Test.lastPromise = null; - - value = fn(val); - - lastPromise = Test.lastPromise; - - // If the method returned a promise - // return that promise. If not, - // return the last async helper's promise - if ((value && (value instanceof Test.Promise)) || !lastPromise) { - return value; - } else { - run(function() { - lastPromise = Test.resolve(lastPromise).then(function() { - return value; - }); - }); - return lastPromise; - } - } - - __exports__["default"] = Test; - }); -enifed("ember-views", - ["ember-runtime","ember-views/system/jquery","ember-views/system/utils","ember-views/system/render_buffer","ember-views/system/ext","ember-views/views/states","ember-views/views/core_view","ember-views/views/view","ember-views/views/container_view","ember-views/views/collection_view","ember-views/views/component","ember-views/system/event_dispatcher","ember-views/mixins/view_target_action_support","ember-views/component_lookup","ember-views/views/checkbox","ember-views/mixins/text_support","ember-views/views/text_field","ember-views/views/text_area","ember-views/views/bound_view","ember-views/views/simple_bound_view","ember-views/views/metamorph_view","ember-views/views/select","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __exports__) { - "use strict"; - /** - Ember Views - - @module ember - @submodule ember-views - @requires ember-runtime - @main ember-views - */ - - // BEGIN IMPORTS - var Ember = __dependency1__["default"]; - var jQuery = __dependency2__["default"]; - var isSimpleClick = __dependency3__.isSimpleClick; - var getViewClientRects = __dependency3__.getViewClientRects; - var getViewBoundingClientRect = __dependency3__.getViewBoundingClientRect; - var RenderBuffer = __dependency4__["default"]; - // for the side effect of extending Ember.run.queues - var cloneStates = __dependency6__.cloneStates; - var states = __dependency6__.states; - - var CoreView = __dependency7__["default"]; - var View = __dependency8__["default"]; - var ContainerView = __dependency9__["default"]; - var CollectionView = __dependency10__["default"]; - var Component = __dependency11__["default"]; - - var EventDispatcher = __dependency12__["default"]; - var ViewTargetActionSupport = __dependency13__["default"]; - var ComponentLookup = __dependency14__["default"]; - var Checkbox = __dependency15__["default"]; - var TextSupport = __dependency16__["default"]; - var TextField = __dependency17__["default"]; - var TextArea = __dependency18__["default"]; - - var BoundView = __dependency19__["default"]; - var SimpleBoundView = __dependency20__["default"]; - var _MetamorphView = __dependency21__["default"]; - var _SimpleMetamorphView = __dependency21__._SimpleMetamorphView; - var _Metamorph = __dependency21__._Metamorph; - var Select = __dependency22__.Select; - var SelectOption = __dependency22__.SelectOption; - var SelectOptgroup = __dependency22__.SelectOptgroup; - // END IMPORTS - - /** - Alias for jQuery - - @method $ - @for Ember - */ - - // BEGIN EXPORTS - Ember.$ = jQuery; - - Ember.ViewTargetActionSupport = ViewTargetActionSupport; - Ember.RenderBuffer = RenderBuffer; - - var ViewUtils = Ember.ViewUtils = {}; - ViewUtils.isSimpleClick = isSimpleClick; - ViewUtils.getViewClientRects = getViewClientRects; - ViewUtils.getViewBoundingClientRect = getViewBoundingClientRect; - - Ember.CoreView = CoreView; - Ember.View = View; - Ember.View.states = states; - Ember.View.cloneStates = cloneStates; - Ember.Checkbox = Checkbox; - Ember.TextField = TextField; - Ember.TextArea = TextArea; - - Ember._SimpleBoundView = SimpleBoundView; - Ember._BoundView = BoundView; - Ember._SimpleMetamorphView = _SimpleMetamorphView; - Ember._MetamorphView = _MetamorphView; - Ember._Metamorph = _Metamorph; - Ember.Select = Select; - Ember.SelectOption = SelectOption; - Ember.SelectOptgroup = SelectOptgroup; - - Ember.TextSupport = TextSupport; - Ember.ComponentLookup = ComponentLookup; - Ember.ContainerView = ContainerView; - Ember.CollectionView = CollectionView; - Ember.Component = Component; - Ember.EventDispatcher = EventDispatcher; - // END EXPORTS - - __exports__["default"] = Ember; - }); -enifed("ember-views/attr_nodes/attr_node", - ["ember-metal/streams/utils","ember-metal/run_loop","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var read = __dependency1__.read; - var subscribe = __dependency1__.subscribe; - var unsubscribe = __dependency1__.unsubscribe; - var run = __dependency2__["default"]; - - function AttrNode(attrName, attrValue) { - this.init(attrName, attrValue); - } - - AttrNode.prototype.init = function init(attrName, simpleAttrValue){ - this.isView = true; - - // That these semantics are used is very unfortunate. - this.tagName = ''; - this.classNameBindings = []; - - this.attrName = attrName; - this.attrValue = simpleAttrValue; - this.isDirty = true; - this.lastValue = null; - - subscribe(this.attrValue, this.rerender, this); - }; - - AttrNode.prototype.renderIfDirty = function renderIfDirty(){ - if (this.isDirty) { - var value = read(this.attrValue); - if (value !== this.lastValue) { - this._renderer.renderTree(this, this._parentView); - } else { - this.isDirty = false; - } - } - }; - - AttrNode.prototype.render = function render(buffer) { - this.isDirty = false; - var value = read(this.attrValue); - - this._morph.setContent(value); - - this.lastValue = value; - }; - - AttrNode.prototype.rerender = function render() { - this.isDirty = true; - run.schedule('render', this, this.renderIfDirty); - }; - - AttrNode.prototype.destroy = function render() { - this.isDirty = false; - unsubscribe(this.attrValue, this.rerender, this); - - var parent = this._parentView; - if (parent) { parent.removeChild(this); } - }; - - __exports__["default"] = AttrNode; - }); -enifed("ember-views/attr_nodes/legacy_bind", - ["./attr_node","ember-runtime/system/string","ember-metal/utils","ember-metal/streams/utils","ember-metal/platform/create","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-htmlbars - */ - - var AttrNode = __dependency1__["default"]; - var fmt = __dependency2__.fmt; - var typeOf = __dependency3__.typeOf; - var read = __dependency4__.read; - var create = __dependency5__["default"]; - - function LegacyBindAttrNode(attrName, attrValue) { - this.init(attrName, attrValue); - } - - LegacyBindAttrNode.prototype = create(AttrNode.prototype); - - LegacyBindAttrNode.prototype.render = function render(buffer) { - this.isDirty = false; - var value = read(this.attrValue); - var type = typeOf(value); - - Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [value]), - value === null || value === undefined || type === 'number' || type === 'string' || type === 'boolean'); - - this._morph.setContent(value); - - this.lastValue = value; - }; - - __exports__["default"] = LegacyBindAttrNode; - }); -enifed("ember-views/component_lookup", - ["ember-runtime/system/object","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var EmberObject = __dependency1__["default"]; - - __exports__["default"] = EmberObject.extend({ - lookupFactory: function(name, container) { - - container = container || this.container; - - var fullName = 'component:' + name; - var templateFullName = 'template:components/' + name; - var templateRegistered = container && container.has(templateFullName); - - if (templateRegistered) { - container.injection(fullName, 'layout', templateFullName); - } - - var Component = container.lookupFactory(fullName); - - // Only treat as a component if either the component - // or a template has been registered. - if (templateRegistered || Component) { - if (!Component) { - container.register(fullName, Ember.Component); - Component = container.lookupFactory(fullName); - } - return Component; - } - } - }); - }); -enifed("ember-views/mixins/component_template_deprecation", - ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.deprecate - var get = __dependency2__.get; - var Mixin = __dependency3__.Mixin; - - /** - The ComponentTemplateDeprecation mixin is used to provide a useful - deprecation warning when using either `template` or `templateName` with - a component. The `template` and `templateName` properties specified at - extend time are moved to `layout` and `layoutName` respectively. - - `Ember.ComponentTemplateDeprecation` is used internally by Ember in - `Ember.Component`. - - @class ComponentTemplateDeprecation - @namespace Ember - */ - __exports__["default"] = Mixin.create({ - /** - @private - - Moves `templateName` to `layoutName` and `template` to `layout` at extend - time if a layout is not also specified. - - Note that this currently modifies the mixin themselves, which is technically - dubious but is practically of little consequence. This may change in the - future. - - @method willMergeMixin - @since 1.4.0 - */ - willMergeMixin: function(props) { - // must call _super here to ensure that the ActionHandler - // mixin is setup properly (moves actions -> _actions) - // - // Calling super is only OK here since we KNOW that - // there is another Mixin loaded first. - this._super.apply(this, arguments); - - var deprecatedProperty, replacementProperty; - var layoutSpecified = (props.layoutName || props.layout || get(this, 'layoutName')); - - if (props.templateName && !layoutSpecified) { - deprecatedProperty = 'templateName'; - replacementProperty = 'layoutName'; - - props.layoutName = props.templateName; - delete props['templateName']; - } - - if (props.template && !layoutSpecified) { - deprecatedProperty = 'template'; - replacementProperty = 'layout'; - - props.layout = props.template; - delete props['template']; - } - - Ember.deprecate('Do not specify ' + deprecatedProperty + ' on a Component, use ' + replacementProperty + ' instead.', !deprecatedProperty); - } - }); - }); -enifed("ember-views/mixins/text_support", - ["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/target_action_support","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-views - */ - - var get = __dependency1__.get; - var set = __dependency2__.set; - var Mixin = __dependency3__.Mixin; - var TargetActionSupport = __dependency4__["default"]; - - /** - `TextSupport` is a shared mixin used by both `Ember.TextField` and - `Ember.TextArea`. `TextSupport` adds a number of methods that allow you to - specify a controller action to invoke when a certain event is fired on your - text field or textarea. The specifed controller action would get the current - value of the field passed in as the only argument unless the value of - the field is empty. In that case, the instance of the field itself is passed - in as the only argument. - - Let's use the pressing of the escape key as an example. If you wanted to - invoke a controller action when a user presses the escape key while on your - field, you would use the `escape-press` attribute on your field like so: - - ```handlebars - {{! application.hbs}} - - {{input escape-press='alertUser'}} - ``` - - ```javascript - App = Ember.Application.create(); - - App.ApplicationController = Ember.Controller.extend({ - actions: { - alertUser: function ( currentValue ) { - alert( 'escape pressed, current value: ' + currentValue ); - } - } - }); - ``` - - The following chart is a visual representation of what takes place when the - escape key is pressed in this scenario: - - The Template - +---------------------------+ - | | - | escape-press='alertUser' | - | | TextSupport Mixin - +----+----------------------+ +-------------------------------+ - | | cancel method | - | escape button pressed | | - +-------------------------------> | checks for the `escape-press` | - | attribute and pulls out the | - +-------------------------------+ | `alertUser` value | - | action name 'alertUser' +-------------------------------+ - | sent to controller - v - Controller - +------------------------------------------ + - | | - | actions: { | - | alertUser: function( currentValue ){ | - | alert( 'the esc key was pressed!' ) | - | } | - | } | - | | - +-------------------------------------------+ - - Here are the events that we currently support along with the name of the - attribute you would need to use on your field. To reiterate, you would use the - attribute name like so: - - ```handlebars - {{input attribute-name='controllerAction'}} - ``` - - +--------------------+----------------+ - | | | - | event | attribute name | - +--------------------+----------------+ - | new line inserted | insert-newline | - | | | - | enter key pressed | insert-newline | - | | | - | cancel key pressed | escape-press | - | | | - | focusin | focus-in | - | | | - | focusout | focus-out | - | | | - | keypress | key-press | - | | | - | keyup | key-up | - | | | - | keydown | key-down | - +--------------------+----------------+ - - @class TextSupport - @namespace Ember - @uses Ember.TargetActionSupport - @extends Ember.Mixin - @private - */ - var TextSupport = Mixin.create(TargetActionSupport, { - value: "", - - attributeBindings: [ - 'autocapitalize', - 'autocorrect', - 'autofocus', - 'disabled', - 'form', - 'maxlength', - 'placeholder', - 'readonly', - 'required', - 'selectionDirection', - 'spellcheck', - 'tabindex', - 'title' - ], - placeholder: null, - disabled: false, - maxlength: null, - - init: function() { - this._super(); - this.on("paste", this, this._elementValueDidChange); - this.on("cut", this, this._elementValueDidChange); - this.on("input", this, this._elementValueDidChange); - }, - - /** - The action to be sent when the user presses the return key. - - This is similar to the `{{action}}` helper, but is fired when - the user presses the return key when editing a text field, and sends - the value of the field as the context. - - @property action - @type String - @default null - */ - action: null, - - /** - The event that should send the action. - - Options are: - - * `enter`: the user pressed enter - * `keyPress`: the user pressed a key - - @property onEvent - @type String - @default enter - */ - onEvent: 'enter', - - /** - Whether the `keyUp` event that triggers an `action` to be sent continues - propagating to other views. - - By default, when the user presses the return key on their keyboard and - the text field has an `action` set, the action will be sent to the view's - controller and the key event will stop propagating. - - If you would like parent views to receive the `keyUp` event even after an - action has been dispatched, set `bubbles` to true. - - @property bubbles - @type Boolean - @default false - */ - bubbles: false, - - interpretKeyEvents: function(event) { - var map = TextSupport.KEY_EVENTS; - var method = map[event.keyCode]; - - this._elementValueDidChange(); - if (method) { return this[method](event); } - }, - - _elementValueDidChange: function() { - set(this, 'value', this.$().val()); - }, - - change: function(event) { - this._elementValueDidChange(event); - }, - - /** - Allows you to specify a controller action to invoke when either the `enter` - key is pressed or, in the case of the field being a textarea, when a newline - is inserted. To use this method, give your field an `insert-newline` - attribute. The value of that attribute should be the name of the action - in your controller that you wish to invoke. - - For an example on how to use the `insert-newline` attribute, please - reference the example near the top of this file. - - @method insertNewline - @param {Event} event - */ - insertNewline: function(event) { - sendAction('enter', this, event); - sendAction('insert-newline', this, event); - }, - - /** - Allows you to specify a controller action to invoke when the escape button - is pressed. To use this method, give your field an `escape-press` - attribute. The value of that attribute should be the name of the action - in your controller that you wish to invoke. - - For an example on how to use the `escape-press` attribute, please reference - the example near the top of this file. - - @method cancel - @param {Event} event - */ - cancel: function(event) { - sendAction('escape-press', this, event); - }, - - /** - Allows you to specify a controller action to invoke when a field receives - focus. To use this method, give your field a `focus-in` attribute. The value - of that attribute should be the name of the action in your controller - that you wish to invoke. - - For an example on how to use the `focus-in` attribute, please reference the - example near the top of this file. - - @method focusIn - @param {Event} event - */ - focusIn: function(event) { - sendAction('focus-in', this, event); - }, - - /** - Allows you to specify a controller action to invoke when a field loses - focus. To use this method, give your field a `focus-out` attribute. The value - of that attribute should be the name of the action in your controller - that you wish to invoke. - - For an example on how to use the `focus-out` attribute, please reference the - example near the top of this file. - - @method focusOut - @param {Event} event - */ - focusOut: function(event) { - this._elementValueDidChange(event); - sendAction('focus-out', this, event); - }, - - /** - Allows you to specify a controller action to invoke when a key is pressed. - To use this method, give your field a `key-press` attribute. The value of - that attribute should be the name of the action in your controller you - that wish to invoke. - - For an example on how to use the `key-press` attribute, please reference the - example near the top of this file. - - @method keyPress - @param {Event} event - */ - keyPress: function(event) { - sendAction('key-press', this, event); - }, - - /** - Allows you to specify a controller action to invoke when a key-up event is - fired. To use this method, give your field a `key-up` attribute. The value - of that attribute should be the name of the action in your controller - that you wish to invoke. - - For an example on how to use the `key-up` attribute, please reference the - example near the top of this file. - - @method keyUp - @param {Event} event - */ - keyUp: function(event) { - this.interpretKeyEvents(event); - - this.sendAction('key-up', get(this, 'value'), event); - }, - - /** - Allows you to specify a controller action to invoke when a key-down event is - fired. To use this method, give your field a `key-down` attribute. The value - of that attribute should be the name of the action in your controller that - you wish to invoke. - - For an example on how to use the `key-down` attribute, please reference the - example near the top of this file. - - @method keyDown - @param {Event} event - */ - keyDown: function(event) { - this.sendAction('key-down', get(this, 'value'), event); - } - }); - - TextSupport.KEY_EVENTS = { - 13: 'insertNewline', - 27: 'cancel' - }; - - // In principle, this shouldn't be necessary, but the legacy - // sendAction semantics for TextField are different from - // the component semantics so this method normalizes them. - function sendAction(eventName, view, event) { - var action = get(view, eventName); - var on = get(view, 'onEvent'); - var value = get(view, 'value'); - - // back-compat support for keyPress as an event name even though - // it's also a method name that consumes the event (and therefore - // incompatible with sendAction semantics). - if (on === eventName || (on === 'keyPress' && eventName === 'key-press')) { - view.sendAction('action', value); - } - - view.sendAction(eventName, value); - - if (action || on === eventName) { - if(!get(view, 'bubbles')) { - event.stopPropagation(); - } - } - } - - __exports__["default"] = TextSupport; - }); -enifed("ember-views/mixins/view_target_action_support", - ["ember-metal/mixin","ember-runtime/mixins/target_action_support","ember-metal/alias","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Mixin = __dependency1__.Mixin; - var TargetActionSupport = __dependency2__["default"]; - var alias = __dependency3__["default"]; - - /** - `Ember.ViewTargetActionSupport` is a mixin that can be included in a - view class to add a `triggerAction` method with semantics similar to - the Handlebars `{{action}}` helper. It provides intelligent defaults - for the action's target: the view's controller; and the context that is - sent with the action: the view's context. - - Note: In normal Ember usage, the `{{action}}` helper is usually the best - choice. This mixin is most often useful when you are doing more complex - event handling in custom View subclasses. - - For example: - - ```javascript - App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { - action: 'save', - click: function() { - this.triggerAction(); // Sends the `save` action, along with the current context - // to the current controller - } - }); - ``` - - The `action` can be provided as properties of an optional object argument - to `triggerAction` as well. - - ```javascript - App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { - click: function() { - this.triggerAction({ - action: 'save' - }); // Sends the `save` action, along with the current context - // to the current controller - } - }); - ``` - - @class ViewTargetActionSupport - @namespace Ember - @extends Ember.TargetActionSupport - */ - __exports__["default"] = Mixin.create(TargetActionSupport, { - /** - @property target - */ - target: alias('controller'), - /** - @property actionContext - */ - actionContext: alias('context') - }); - }); -enifed("ember-views/streams/class_name_binding", - ["ember-metal/streams/utils","ember-metal/property_get","ember-runtime/system/string","ember-metal/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var chain = __dependency1__.chain; - var read = __dependency1__.read; - var get = __dependency2__.get; - var dasherize = __dependency3__.dasherize; - var isArray = __dependency4__.isArray; - - /** - Parse a path and return an object which holds the parsed properties. - - For example a path like "content.isEnabled:enabled:disabled" will return the - following object: - - ```javascript - { - path: "content.isEnabled", - className: "enabled", - falsyClassName: "disabled", - classNames: ":enabled:disabled" - } - ``` - - @method parsePropertyPath - @static - @private - */ - function parsePropertyPath(path) { - var split = path.split(':'); - var propertyPath = split[0]; - var classNames = ""; - var className, falsyClassName; - - // check if the property is defined as prop:class or prop:trueClass:falseClass - if (split.length > 1) { - className = split[1]; - if (split.length === 3) { - falsyClassName = split[2]; - } - - classNames = ':' + className; - if (falsyClassName) { - classNames += ":" + falsyClassName; - } - } - - return { - path: propertyPath, - classNames: classNames, - className: (className === '') ? undefined : className, - falsyClassName: falsyClassName - }; - } - - __exports__.parsePropertyPath = parsePropertyPath;/** - Get the class name for a given value, based on the path, optional - `className` and optional `falsyClassName`. - - - if a `className` or `falsyClassName` has been specified: - - if the value is truthy and `className` has been specified, - `className` is returned - - if the value is falsy and `falsyClassName` has been specified, - `falsyClassName` is returned - - otherwise `null` is returned - - if the value is `true`, the dasherized last part of the supplied path - is returned - - if the value is not `false`, `undefined` or `null`, the `value` - is returned - - if none of the above rules apply, `null` is returned - - @method classStringForValue - @param path - @param val - @param className - @param falsyClassName - @static - @private - */ - function classStringForValue(path, val, className, falsyClassName) { - if(isArray(val)) { - val = get(val, 'length') !== 0; - } - - // When using the colon syntax, evaluate the truthiness or falsiness - // of the value to determine which className to return - if (className || falsyClassName) { - if (className && !!val) { - return className; - - } else if (falsyClassName && !val) { - return falsyClassName; - - } else { - return null; - } - - // If value is a Boolean and true, return the dasherized property - // name. - } else if (val === true) { - // Normalize property path to be suitable for use - // as a class name. For exaple, content.foo.barBaz - // becomes bar-baz. - var parts = path.split('.'); - return dasherize(parts[parts.length-1]); - - // If the value is not false, undefined, or null, return the current - // value of the property. - } else if (val !== false && val != null) { - return val; - - // Nothing to display. Return null so that the old class is removed - // but no new class is added. - } else { - return null; - } - } - - __exports__.classStringForValue = classStringForValue;function streamifyClassNameBinding(view, classNameBinding, prefix){ - prefix = prefix || ''; - Ember.assert("classNameBindings must not have spaces in them. Multiple class name bindings can be provided as elements of an array, e.g. ['foo', ':bar']", classNameBinding.indexOf(' ') === -1); - var parsedPath = parsePropertyPath(classNameBinding); - if (parsedPath.path === '') { - return classStringForValue( - parsedPath.path, - true, - parsedPath.className, - parsedPath.falsyClassName - ); - } else { - var pathValue = view.getStream(prefix+parsedPath.path); - return chain(pathValue, function() { - return classStringForValue( - parsedPath.path, - read(pathValue), - parsedPath.className, - parsedPath.falsyClassName - ); - }); - } - } - - __exports__.streamifyClassNameBinding = streamifyClassNameBinding; - }); -enifed("ember-views/streams/conditional_stream", - ["ember-metal/streams/stream","ember-metal/streams/utils","ember-metal/platform","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Stream = __dependency1__["default"]; - var read = __dependency2__.read; - var subscribe = __dependency2__.subscribe; - var unsubscribe = __dependency2__.unsubscribe; - var create = __dependency3__.create; - - function ConditionalStream(test, consequent, alternate) { - this.init(); - - this.oldTestResult = undefined; - this.test = test; - this.consequent = consequent; - this.alternate = alternate; - } - - ConditionalStream.prototype = create(Stream.prototype); - - ConditionalStream.prototype.valueFn = function() { - var oldTestResult = this.oldTestResult; - var newTestResult = !!read(this.test); - - if (newTestResult !== oldTestResult) { - switch (oldTestResult) { - case true: unsubscribe(this.consequent, this.notify, this); break; - case false: unsubscribe(this.alternate, this.notify, this); break; - case undefined: subscribe(this.test, this.notify, this); - } - - switch (newTestResult) { - case true: subscribe(this.consequent, this.notify, this); break; - case false: subscribe(this.alternate, this.notify, this); - } - - this.oldTestResult = newTestResult; - } - - return newTestResult ? read(this.consequent) : read(this.alternate); - }; - - __exports__["default"] = ConditionalStream; - }); -enifed("ember-views/streams/context_stream", - ["ember-metal/core","ember-metal/merge","ember-metal/platform","ember-metal/path_cache","ember-metal/streams/stream","ember-metal/streams/simple","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - - var merge = __dependency2__["default"]; - var create = __dependency3__.create; - var isGlobal = __dependency4__.isGlobal; - var Stream = __dependency5__["default"]; - var SimpleStream = __dependency6__["default"]; - - function ContextStream(view) { - Ember.assert("ContextStream error: the argument is not a view", view && view.isView); - - this.init(); - this.view = view; - } - - ContextStream.prototype = create(Stream.prototype); - - merge(ContextStream.prototype, { - value: function() {}, - - _makeChildStream: function(key, _fullPath) { - var stream; - - if (key === '' || key === 'this') { - stream = this.view._baseContext; - } else if (isGlobal(key) && Ember.lookup[key]) { - Ember.deprecate("Global lookup of " + _fullPath + " from a Handlebars template is deprecated."); - stream = new SimpleStream(Ember.lookup[key]); - stream._isGlobal = true; - } else if (key in this.view._keywords) { - stream = new SimpleStream(this.view._keywords[key]); - } else { - stream = new SimpleStream(this.view._baseContext.get(key)); - } - - stream._isRoot = true; - - if (key === 'controller') { - stream._isController = true; - } - - return stream; - } - }); - - __exports__["default"] = ContextStream; - }); -enifed("ember-views/streams/key_stream", - ["ember-metal/core","ember-metal/merge","ember-metal/platform","ember-metal/property_get","ember-metal/property_set","ember-metal/observer","ember-metal/streams/stream","ember-metal/streams/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - - var merge = __dependency2__["default"]; - var create = __dependency3__.create; - var get = __dependency4__.get; - var set = __dependency5__.set; - var addObserver = __dependency6__.addObserver; - var removeObserver = __dependency6__.removeObserver; - var Stream = __dependency7__["default"]; - var read = __dependency8__.read; - var isStream = __dependency8__.isStream; - - function KeyStream(source, key) { - Ember.assert("KeyStream error: key must be a non-empty string", typeof key === 'string' && key.length > 0); - Ember.assert("KeyStream error: key must not have a '.'", key.indexOf('.') === -1); - - this.init(); - this.source = source; - this.obj = undefined; - this.key = key; - - if (isStream(source)) { - source.subscribe(this._didChange, this); - } - } - - KeyStream.prototype = create(Stream.prototype); - - merge(KeyStream.prototype, { - valueFn: function() { - var prevObj = this.obj; - var nextObj = read(this.source); - - if (nextObj !== prevObj) { - if (prevObj && typeof prevObj === 'object') { - removeObserver(prevObj, this.key, this, this._didChange); - } - - if (nextObj && typeof nextObj === 'object') { - addObserver(nextObj, this.key, this, this._didChange); - } - - this.obj = nextObj; - } - - if (nextObj) { - return get(nextObj, this.key); - } - }, - - setValue: function(value) { - if (this.obj) { - set(this.obj, this.key, value); - } - }, - - setSource: function(nextSource) { - Ember.assert("KeyStream error: source must be an object", typeof nextSource === 'object'); - - var prevSource = this.source; - - if (nextSource !== prevSource) { - if (isStream(prevSource)) { - prevSource.unsubscribe(this._didChange, this); - } - - if (isStream(nextSource)) { - nextSource.subscribe(this._didChange, this); - } - - this.source = nextSource; - this.notify(); - } - }, - - _didChange: function() { - this.notify(); - }, - - _super$destroy: Stream.prototype.destroy, - - destroy: function() { - if (this._super$destroy()) { - if (isStream(this.source)) { - this.source.unsubscribe(this._didChange, this); - } - - if (this.obj && typeof this.obj === 'object') { - removeObserver(this.obj, this.key, this, this._didChange); - } - - this.source = undefined; - this.obj = undefined; - return true; - } - } - }); - - __exports__["default"] = KeyStream; - - // The transpiler does not resolve cycles, so we export - // the `_makeChildStream` method onto `Stream` here. - - Stream.prototype._makeChildStream = function(key) { - return new KeyStream(this, key); - }; - }); -enifed("ember-views/streams/utils", - ["ember-metal/core","ember-metal/property_get","ember-metal/path_cache","ember-runtime/system/string","ember-metal/streams/utils","ember-views/views/view","ember-runtime/mixins/controller","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var get = __dependency2__.get; - var isGlobal = __dependency3__.isGlobal; - var fmt = __dependency4__.fmt; - var read = __dependency5__.read; - var isStream = __dependency5__.isStream; - var View = __dependency6__["default"]; - var ControllerMixin = __dependency7__["default"]; - - function readViewFactory(object, container) { - var value = read(object); - var viewClass; - - if (typeof value === 'string') { - if (isGlobal(value)) { - viewClass = get(null, value); - Ember.deprecate('Resolved the view "'+value+'" on the global context. Pass a view name to be looked up on the container instead, such as {{view "select"}}.', !viewClass, { url: 'http://emberjs.com/guides/deprecations/#toc_global-lookup-of-views' }); - } else { - Ember.assert("View requires a container to resolve views not passed in through the context", !!container); - viewClass = container.lookupFactory('view:'+value); - } - } else { - viewClass = value; - } - - Ember.assert(fmt(value+" must be a subclass or an instance of Ember.View, not %@", [viewClass]), View.detect(viewClass) || View.detectInstance(viewClass)); - - return viewClass; - } - - __exports__.readViewFactory = readViewFactory;function readUnwrappedModel(object) { - if (isStream(object)) { - var result = object.value(); - - // If the path is exactly `controller` then we don't unwrap it. - if (!object._isController) { - while (ControllerMixin.detect(result)) { - result = get(result, 'model'); - } - } - - return result; - } else { - return object; - } - } - - __exports__.readUnwrappedModel = readUnwrappedModel; - }); -enifed("ember-views/system/action_manager", - ["exports"], - function(__exports__) { - "use strict"; - /** - @module ember - @submodule ember-views - */ - - function ActionManager() {} - - /** - Global action id hash. - - @private - @property registeredActions - @type Object - */ - ActionManager.registeredActions = {}; - - __exports__["default"] = ActionManager; - }); -enifed("ember-views/system/event_dispatcher", - ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/object","ember-views/system/jquery","ember-views/system/action_manager","ember-views/views/view","ember-metal/merge","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-views - */ - var Ember = __dependency1__["default"]; - // Ember.assert - - var get = __dependency2__.get; - var set = __dependency3__.set; - var isNone = __dependency4__["default"]; - var run = __dependency5__["default"]; - var typeOf = __dependency6__.typeOf; - var fmt = __dependency7__.fmt; - var EmberObject = __dependency8__["default"]; - var jQuery = __dependency9__["default"]; - var ActionManager = __dependency10__["default"]; - var View = __dependency11__["default"]; - var merge = __dependency12__["default"]; - - //ES6TODO: - // find a better way to do Ember.View.views without global state - - /** - `Ember.EventDispatcher` handles delegating browser events to their - corresponding `Ember.Views.` For example, when you click on a view, - `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets - called. - - @class EventDispatcher - @namespace Ember - @private - @extends Ember.Object - */ - __exports__["default"] = EmberObject.extend({ - - /** - The set of events names (and associated handler function names) to be setup - and dispatched by the `EventDispatcher`. Custom events can added to this list at setup - time, generally via the `Ember.Application.customEvents` hash. Only override this - default set to prevent the EventDispatcher from listening on some events all together. - - This set will be modified by `setup` to also include any events added at that time. - - @property events - @type Object - */ - events: { - touchstart : 'touchStart', - touchmove : 'touchMove', - touchend : 'touchEnd', - touchcancel : 'touchCancel', - keydown : 'keyDown', - keyup : 'keyUp', - keypress : 'keyPress', - mousedown : 'mouseDown', - mouseup : 'mouseUp', - contextmenu : 'contextMenu', - click : 'click', - dblclick : 'doubleClick', - mousemove : 'mouseMove', - focusin : 'focusIn', - focusout : 'focusOut', - mouseenter : 'mouseEnter', - mouseleave : 'mouseLeave', - submit : 'submit', - input : 'input', - change : 'change', - dragstart : 'dragStart', - drag : 'drag', - dragenter : 'dragEnter', - dragleave : 'dragLeave', - dragover : 'dragOver', - drop : 'drop', - dragend : 'dragEnd' - }, - - /** - The root DOM element to which event listeners should be attached. Event - listeners will be attached to the document unless this is overridden. - - Can be specified as a DOMElement or a selector string. - - The default body is a string since this may be evaluated before document.body - exists in the DOM. - - @private - @property rootElement - @type DOMElement - @default 'body' - */ - rootElement: 'body', - - /** - It enables events to be dispatched to the view's `eventManager.` When present, - this object takes precedence over handling of events on the view itself. - - Note that most Ember applications do not use this feature. If your app also - does not use it, consider setting this property to false to gain some performance - improvement by allowing the EventDispatcher to skip the search for the - `eventManager` on the view tree. - - ```javascript - var EventDispatcher = Em.EventDispatcher.extend({ - events: { - click : 'click', - focusin : 'focusIn', - focusout : 'focusOut', - change : 'change' - }, - canDispatchToEventManager: false - }); - container.register('event_dispatcher:main', EventDispatcher); - ``` - - @property canDispatchToEventManager - @type boolean - @default 'true' - @since 1.7.0 - */ - canDispatchToEventManager: true, - - /** - Sets up event listeners for standard browser events. - - This will be called after the browser sends a `DOMContentReady` event. By - default, it will set up all of the listeners on the document body. If you - would like to register the listeners on a different element, set the event - dispatcher's `root` property. - - @private - @method setup - @param addedEvents {Hash} - */ - setup: function(addedEvents, rootElement) { - var event, events = get(this, 'events'); - - merge(events, addedEvents || {}); - - if (!isNone(rootElement)) { - set(this, 'rootElement', rootElement); - } - - rootElement = jQuery(get(this, 'rootElement')); - - Ember.assert(fmt('You cannot use the same root element (%@) multiple times in an Ember.Application', [rootElement.selector || rootElement[0].tagName]), !rootElement.is('.ember-application')); - Ember.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest('.ember-application').length); - Ember.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find('.ember-application').length); - - rootElement.addClass('ember-application'); - - Ember.assert('Unable to add "ember-application" class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is('.ember-application')); - - for (event in events) { - if (events.hasOwnProperty(event)) { - this.setupHandler(rootElement, event, events[event]); - } - } - }, - - /** - Registers an event listener on the rootElement. If the given event is - triggered, the provided event handler will be triggered on the target view. - - If the target view does not implement the event handler, or if the handler - returns `false`, the parent view will be called. The event will continue to - bubble to each successive parent view until it reaches the top. - - @private - @method setupHandler - @param {Element} rootElement - @param {String} event the browser-originated event to listen to - @param {String} eventName the name of the method to call on the view - */ - setupHandler: function(rootElement, event, eventName) { - var self = this; - - rootElement.on(event + '.ember', '.ember-view', function(evt, triggeringManager) { - var view = View.views[this.id]; - var result = true; - - var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null; - - if (manager && manager !== triggeringManager) { - result = self._dispatchEvent(manager, evt, eventName, view); - } else if (view) { - result = self._bubbleEvent(view, evt, eventName); - } - - return result; - }); - - rootElement.on(event + '.ember', '[data-ember-action]', function(evt) { - var actionId = jQuery(evt.currentTarget).attr('data-ember-action'); - var action = ActionManager.registeredActions[actionId]; - - // We have to check for action here since in some cases, jQuery will trigger - // an event on `removeChild` (i.e. focusout) after we've already torn down the - // action handlers for the view. - if (action && action.eventName === eventName) { - return action.handler(evt); - } - }); - }, - - _findNearestEventManager: function(view, eventName) { - var manager = null; - - while (view) { - manager = get(view, 'eventManager'); - if (manager && manager[eventName]) { break; } - - view = get(view, 'parentView'); - } - - return manager; - }, - - _dispatchEvent: function(object, evt, eventName, view) { - var result = true; - - var handler = object[eventName]; - if (typeOf(handler) === 'function') { - result = run(object, handler, evt, view); - // Do not preventDefault in eventManagers. - evt.stopPropagation(); - } - else { - result = this._bubbleEvent(view, evt, eventName); - } - - return result; - }, - - _bubbleEvent: function(view, evt, eventName) { - return run.join(view, view.handleEvent, eventName, evt); - }, - - destroy: function() { - var rootElement = get(this, 'rootElement'); - jQuery(rootElement).off('.ember', '**').removeClass('ember-application'); - return this._super(); - }, - - toString: function() { - return '(EventDispatcher)'; - } - }); - }); -enifed("ember-views/system/ext", - ["ember-metal/run_loop"], - function(__dependency1__) { - "use strict"; - /** - @module ember - @submodule ember-views - */ - - var run = __dependency1__["default"]; - - // Add a new named queue for rendering views that happens - // after bindings have synced, and a queue for scheduling actions - // that that should occur after view rendering. - run._addQueue('render', 'actions'); - run._addQueue('afterRender', 'render'); - }); -enifed("ember-views/system/jquery", - ["ember-metal/core","ember-metal/enumerable_utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - - // ES6TODO: the functions on EnumerableUtils need their own exports - var forEach = __dependency2__.forEach; - - /** - Ember Views - - @module ember - @submodule ember-views - @requires ember-runtime - @main ember-views - */ - - var jQuery = (Ember.imports && Ember.imports.jQuery) || (this && this.jQuery); - if (!jQuery && typeof eriuqer === 'function') { - jQuery = eriuqer('jquery'); - } - - Ember.assert("Ember Views require jQuery between 1.7 and 2.1", jQuery && - (jQuery().jquery.match(/^((1\.(7|8|9|10|11))|(2\.(0|1)))(\.\d+)?(pre|rc\d?)?/) || - Ember.ENV.FORCE_JQUERY)); - - /** - @module ember - @submodule ember-views - */ - if (jQuery) { - // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents - var dragEvents = [ - 'dragstart', - 'drag', - 'dragenter', - 'dragleave', - 'dragover', - 'drop', - 'dragend' - ]; - - // Copies the `dataTransfer` property from a browser event object onto the - // jQuery event object for the specified events - forEach(dragEvents, function(eventName) { - jQuery.event.fixHooks[eventName] = { - props: ['dataTransfer'] - }; - }); - } - - __exports__["default"] = jQuery; - }); -enifed("ember-views/system/render_buffer", - ["ember-views/system/jquery","morph","ember-metal/core","ember-metal/platform","morph/dom-helper/prop","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-views - */ - - var jQuery = __dependency1__["default"]; - var DOMHelper = __dependency2__.DOMHelper; - var Ember = __dependency3__["default"]; - var create = __dependency4__.create; - var normalizeProperty = __dependency5__.normalizeProperty; - - // The HTML spec allows for "omitted start tags". These tags are optional - // when their intended child is the first thing in the parent tag. For - // example, this is a tbody start tag: - // - // - // - // - // - // The tbody may be omitted, and the browser will accept and render: - // - //
    - // - // - // However, the omitted start tag will still be added to the DOM. Here - // we test the string and context to see if the browser is about to - // perform this cleanup, but with a special allowance for disregarding - // - ``` - - And associate it by name using a view's `templateName` property: - - ```javascript - AView = Ember.View.extend({ - templateName: 'some-template' - }); - ``` - - If you have nested resources, your Handlebars template will look like this: - - ```html - - ``` - - And `templateName` property: - - ```javascript - AView = Ember.View.extend({ - templateName: 'posts/new' - }); - ``` - - Using a value for `templateName` that does not have a Handlebars template - with a matching `data-template-name` attribute will throw an error. - - For views classes that may have a template later defined (e.g. as the block - portion of a `{{view}}` Handlebars helper call in another template or in - a subclass), you can provide a `defaultTemplate` property set to compiled - template function. If a template is not later provided for the view instance - the `defaultTemplate` value will be used: - - ```javascript - AView = Ember.View.extend({ - defaultTemplate: Ember.Handlebars.compile('I was the default'), - template: null, - templateName: null - }); - ``` - - Will result in instances with an HTML representation of: - - ```html -
    I was the default
    - ``` - - If a `template` or `templateName` is provided it will take precedence over - `defaultTemplate`: - - ```javascript - AView = Ember.View.extend({ - defaultTemplate: Ember.Handlebars.compile('I was the default') - }); - - aView = AView.create({ - template: Ember.Handlebars.compile('I was the template, not default') - }); - ``` - - Will result in the following HTML representation when rendered: - - ```html -
    I was the template, not default
    - ``` - - ## View Context - - The default context of the compiled template is the view's controller: - - ```javascript - AView = Ember.View.extend({ - template: Ember.Handlebars.compile('Hello {{excitedGreeting}}') - }); - - aController = Ember.Object.create({ - firstName: 'Barry', - excitedGreeting: function() { - return this.get("content.firstName") + "!!!" - }.property() - }); - - aView = AView.create({ - controller: aController - }); - ``` - - Will result in an HTML representation of: - - ```html -
    Hello Barry!!!
    - ``` - - A context can also be explicitly supplied through the view's `context` - property. If the view has neither `context` nor `controller` properties, the - `parentView`'s context will be used. - - ## Layouts - - Views can have a secondary template that wraps their main template. Like - primary templates, layouts can be any function that accepts an optional - context parameter and returns a string of HTML that will be inserted inside - view's tag. Views whose HTML element is self closing (e.g. ``) - cannot have a layout and this property will be ignored. - - Most typically in Ember a layout will be a compiled `Ember.Handlebars` - template. - - A view's layout can be set directly with the `layout` property or reference - an existing Handlebars template by name with the `layoutName` property. - - A template used as a layout must contain a single use of the Handlebars - `{{yield}}` helper. The HTML contents of a view's rendered `template` will be - inserted at this location: - - ```javascript - AViewWithLayout = Ember.View.extend({ - layout: Ember.Handlebars.compile("
    {{yield}}
    "), - template: Ember.Handlebars.compile("I got wrapped") - }); - ``` - - Will result in view instances with an HTML representation of: - - ```html -
    -
    - I got wrapped -
    -
    - ``` - - See [Ember.Handlebars.helpers.yield](/api/classes/Ember.Handlebars.helpers.html#method_yield) - for more information. - - ## Responding to Browser Events - - Views can respond to user-initiated events in one of three ways: method - implementation, through an event manager, and through `{{action}}` helper use - in their template or layout. - - ### Method Implementation - - Views can respond to user-initiated events by implementing a method that - matches the event name. A `jQuery.Event` object will be passed as the - argument to this method. - - ```javascript - AView = Ember.View.extend({ - click: function(event) { - // will be called when when an instance's - // rendered element is clicked - } - }); - ``` - - ### Event Managers - - Views can define an object as their `eventManager` property. This object can - then implement methods that match the desired event names. Matching events - that occur on the view's rendered HTML or the rendered HTML of any of its DOM - descendants will trigger this method. A `jQuery.Event` object will be passed - as the first argument to the method and an `Ember.View` object as the - second. The `Ember.View` will be the view whose rendered HTML was interacted - with. This may be the view with the `eventManager` property or one of its - descendent views. - - ```javascript - AView = Ember.View.extend({ - eventManager: Ember.Object.create({ - doubleClick: function(event, view) { - // will be called when when an instance's - // rendered element or any rendering - // of this views's descendent - // elements is clicked - } - }) - }); - ``` - - An event defined for an event manager takes precedence over events of the - same name handled through methods on the view. - - ```javascript - AView = Ember.View.extend({ - mouseEnter: function(event) { - // will never trigger. - }, - eventManager: Ember.Object.create({ - mouseEnter: function(event, view) { - // takes precedence over AView#mouseEnter - } - }) - }); - ``` - - Similarly a view's event manager will take precedence for events of any views - rendered as a descendent. A method name that matches an event name will not - be called if the view instance was rendered inside the HTML representation of - a view that has an `eventManager` property defined that handles events of the - name. Events not handled by the event manager will still trigger method calls - on the descendent. - - ```javascript - var App = Ember.Application.create(); - App.OuterView = Ember.View.extend({ - template: Ember.Handlebars.compile("outer {{#view 'inner'}}inner{{/view}} outer"), - eventManager: Ember.Object.create({ - mouseEnter: function(event, view) { - // view might be instance of either - // OuterView or InnerView depending on - // where on the page the user interaction occurred - } - }) - }); - - App.InnerView = Ember.View.extend({ - click: function(event) { - // will be called if rendered inside - // an OuterView because OuterView's - // eventManager doesn't handle click events - }, - mouseEnter: function(event) { - // will never be called if rendered inside - // an OuterView. - } - }); - ``` - - ### Handlebars `{{action}}` Helper - - See [Handlebars.helpers.action](/api/classes/Ember.Handlebars.helpers.html#method_action). - - ### Event Names - - All of the event handling approaches described above respond to the same set - of events. The names of the built-in events are listed below. (The hash of - built-in events exists in `Ember.EventDispatcher`.) Additional, custom events - can be registered by using `Ember.Application.customEvents`. - - Touch events: - - * `touchStart` - * `touchMove` - * `touchEnd` - * `touchCancel` - - Keyboard events - - * `keyDown` - * `keyUp` - * `keyPress` - - Mouse events - - * `mouseDown` - * `mouseUp` - * `contextMenu` - * `click` - * `doubleClick` - * `mouseMove` - * `focusIn` - * `focusOut` - * `mouseEnter` - * `mouseLeave` - - Form events: - - * `submit` - * `change` - * `focusIn` - * `focusOut` - * `input` - - HTML5 drag and drop events: - - * `dragStart` - * `drag` - * `dragEnter` - * `dragLeave` - * `dragOver` - * `dragEnd` - * `drop` - - ## Handlebars `{{view}}` Helper - - Other `Ember.View` instances can be included as part of a view's template by - using the `{{view}}` Handlebars helper. See [Ember.Handlebars.helpers.view](/api/classes/Ember.Handlebars.helpers.html#method_view) - for additional information. - - @class View - @namespace Ember - @extends Ember.CoreView - */ - var View = CoreView.extend({ - - concatenatedProperties: ['classNames', 'classNameBindings', 'attributeBindings'], - - /** - @property isView - @type Boolean - @default true - @static - */ - isView: true, - - // .......................................................... - // TEMPLATE SUPPORT - // - - /** - The name of the template to lookup if no template is provided. - - By default `Ember.View` will lookup a template with this name in - `Ember.TEMPLATES` (a shared global object). - - @property templateName - @type String - @default null - */ - templateName: null, - - /** - The name of the layout to lookup if no layout is provided. - - By default `Ember.View` will lookup a template with this name in - `Ember.TEMPLATES` (a shared global object). - - @property layoutName - @type String - @default null - */ - layoutName: null, - - /** - Used to identify this view during debugging - - @property instrumentDisplay - @type String - */ - instrumentDisplay: computed(function() { - if (this.helperName) { - return '{{' + this.helperName + '}}'; - } - }), - - /** - The template used to render the view. This should be a function that - accepts an optional context parameter and returns a string of HTML that - will be inserted into the DOM relative to its parent view. - - In general, you should set the `templateName` property instead of setting - the template yourself. - - @property template - @type Function - */ - template: computed('templateName', function(key, value) { - if (value !== undefined) { return value; } - - var templateName = get(this, 'templateName'); - var template = this.templateForName(templateName, 'template'); - - Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || !!template); - - return template || get(this, 'defaultTemplate'); - }), - - _controller: null, - - /** - The controller managing this view. If this property is set, it will be - made available for use by the template. - - @property controller - @type Object - */ - controller: computed(function(key, value) { - if (arguments.length === 2) { - this._controller = value; - return value; - } - - if (this._controller) { - return this._controller; - } - - var parentView = get(this, '_parentView'); - return parentView ? get(parentView, 'controller') : null; - }), - - /** - A view may contain a layout. A layout is a regular template but - supersedes the `template` property during rendering. It is the - responsibility of the layout template to retrieve the `template` - property from the view (or alternatively, call `Handlebars.helpers.yield`, - `{{yield}}`) to render it in the correct location. - - This is useful for a view that has a shared wrapper, but which delegates - the rendering of the contents of the wrapper to the `template` property - on a subclass. - - @property layout - @type Function - */ - layout: computed(function(key) { - var layoutName = get(this, 'layoutName'); - var layout = this.templateForName(layoutName, 'layout'); - - Ember.assert("You specified the layoutName " + layoutName + " for " + this + ", but it did not exist.", !layoutName || !!layout); - - return layout || get(this, 'defaultLayout'); - }).property('layoutName'), - - _yield: function(context, options, morph) { - var template = get(this, 'template'); - - if (template) { - var useHTMLBars = false; - - useHTMLBars = template.isHTMLBars; - - - if (useHTMLBars) { - return template.render(this, options, morph.contextualElement); - } else { - return template(context, options); - } - } - }, - - _blockArguments: EMPTY_ARRAY, - - templateForName: function(name, type) { - if (!name) { return; } - Ember.assert("templateNames are not allowed to contain periods: "+name, name.indexOf('.') === -1); - - if (!this.container) { - throw new EmberError('Container was not found when looking up a views template. ' + - 'This is most likely due to manually instantiating an Ember.View. ' + - 'See: http://git.io/EKPpnA'); - } - - return this.container.lookup('template:' + name); - }, - - /** - The object from which templates should access properties. - - This object will be passed to the template function each time the render - method is called, but it is up to the individual function to decide what - to do with it. - - By default, this will be the view's controller. - - @property context - @type Object - */ - context: computed(function(key, value) { - if (arguments.length === 2) { - set(this, '_context', value); - return value; - } else { - return get(this, '_context'); - } - })["volatile"](), - - /** - Private copy of the view's template context. This can be set directly - by Handlebars without triggering the observer that causes the view - to be re-rendered. - - The context of a view is looked up as follows: - - 1. Supplied context (usually by Handlebars) - 2. Specified controller - 3. `parentView`'s context (for a child of a ContainerView) - - The code in Handlebars that overrides the `_context` property first - checks to see whether the view has a specified controller. This is - something of a hack and should be revisited. - - @property _context - @private - */ - _context: computed(function(key, value) { - if (arguments.length === 2) { - return value; - } - - var parentView, controller; - - if (controller = get(this, 'controller')) { - return controller; - } - - parentView = this._parentView; - if (parentView) { - return get(parentView, '_context'); - } - - return null; - }), - - /** - If a value that affects template rendering changes, the view should be - re-rendered to reflect the new value. - - @method _contextDidChange - @private - */ - _contextDidChange: observer('context', function() { - this.rerender(); - }), - - /** - If `false`, the view will appear hidden in DOM. - - @property isVisible - @type Boolean - @default null - */ - isVisible: true, - - /** - Array of child views. You should never edit this array directly. - Instead, use `appendChild` and `removeFromParent`. - - @property childViews - @type Array - @default [] - @private - */ - childViews: childViewsProperty, - - _childViews: EMPTY_ARRAY, - - // When it's a virtual view, we need to notify the parent that their - // childViews will change. - _childViewsWillChange: beforeObserver('childViews', function() { - if (this.isVirtual) { - var parentView = get(this, 'parentView'); - if (parentView) { propertyWillChange(parentView, 'childViews'); } - } - }), - - // When it's a virtual view, we need to notify the parent that their - // childViews did change. - _childViewsDidChange: observer('childViews', function() { - if (this.isVirtual) { - var parentView = get(this, 'parentView'); - if (parentView) { propertyDidChange(parentView, 'childViews'); } - } - }), - - /** - Return the nearest ancestor that is an instance of the provided - class. - - @method nearestInstanceOf - @param {Class} klass Subclass of Ember.View (or Ember.View itself) - @return Ember.View - @deprecated - */ - nearestInstanceOf: function(klass) { - Ember.deprecate("nearestInstanceOf is deprecated and will be removed from future releases. Use nearestOfType."); - var view = get(this, 'parentView'); - - while (view) { - if (view instanceof klass) { return view; } - view = get(view, 'parentView'); - } - }, - - /** - Return the nearest ancestor that is an instance of the provided - class or mixin. - - @method nearestOfType - @param {Class,Mixin} klass Subclass of Ember.View (or Ember.View itself), - or an instance of Ember.Mixin. - @return Ember.View - */ - nearestOfType: function(klass) { - var view = get(this, 'parentView'); - var isOfType = klass instanceof Mixin ? - function(view) { return klass.detect(view); } : - function(view) { return klass.detect(view.constructor); }; - - while (view) { - if (isOfType(view)) { return view; } - view = get(view, 'parentView'); - } - }, - - /** - Return the nearest ancestor that has a given property. - - @method nearestWithProperty - @param {String} property A property name - @return Ember.View - */ - nearestWithProperty: function(property) { - var view = get(this, 'parentView'); - - while (view) { - if (property in view) { return view; } - view = get(view, 'parentView'); - } - }, - - /** - Return the nearest ancestor whose parent is an instance of - `klass`. - - @method nearestChildOf - @param {Class} klass Subclass of Ember.View (or Ember.View itself) - @return Ember.View - */ - nearestChildOf: function(klass) { - var view = get(this, 'parentView'); - - while (view) { - if (get(view, 'parentView') instanceof klass) { return view; } - view = get(view, 'parentView'); - } - }, - - /** - When the parent view changes, recursively invalidate `controller` - - @method _parentViewDidChange - @private - */ - _parentViewDidChange: observer('_parentView', function() { - if (this.isDestroying) { return; } - - this._setupKeywords(); - this.trigger('parentViewDidChange'); - - if (get(this, 'parentView.controller') && !get(this, 'controller')) { - this.notifyPropertyChange('controller'); - } - }), - - _controllerDidChange: observer('controller', function() { - if (this.isDestroying) { return; } - - this.rerender(); - - this.forEachChildView(function(view) { - view.propertyDidChange('controller'); - }); - }), - - _setupKeywords: function() { - var keywords = this._keywords; - var contextView = this._contextView || this._parentView; - - if (contextView) { - var parentKeywords = contextView._keywords; - - keywords.view = this.isVirtual ? parentKeywords.view : this; - - for (var name in parentKeywords) { - if (keywords[name]) continue; - keywords[name] = parentKeywords[name]; - } - } else { - keywords.view = this.isVirtual ? null : this; - } - }, - - /** - Called on your view when it should push strings of HTML into a - `Ember.RenderBuffer`. Most users will want to override the `template` - or `templateName` properties instead of this method. - - By default, `Ember.View` will look for a function in the `template` - property and invoke it with the value of `context`. The value of - `context` will be the view's controller unless you override it. - - @method render - @param {Ember.RenderBuffer} buffer The render buffer - */ - render: function(buffer) { - // If this view has a layout, it is the responsibility of the - // the layout to render the view's template. Otherwise, render the template - // directly. - var template = get(this, 'layout') || get(this, 'template'); - - if (template) { - var context = get(this, 'context'); - var output; - - var data = { - view: this, - buffer: buffer, - isRenderData: true - }; - - // Invoke the template with the provided template context, which - // is the view's controller by default. A hash of data is also passed that provides - // the template with access to the view and render buffer. - - // The template should write directly to the render buffer instead - // of returning a string. - var options = { data: data }; - var useHTMLBars = false; - - - useHTMLBars = template.isHTMLBars; - - - if (useHTMLBars) { - Ember.assert('template must be an object. Did you mean to call Ember.Handlebars.compile("...") or specify templateName instead?', typeof template === 'object'); - var env = Ember.merge(buildHTMLBarsDefaultEnv(), options); - output = template.render(this, env, buffer.innerContextualElement(), this._blockArguments); - } else { - Ember.assert('template must be a function. Did you mean to call Ember.Handlebars.compile("...") or specify templateName instead?', typeof template === 'function'); - output = template(context, options); - } - - // If the template returned a string instead of writing to the buffer, - // push the string onto the buffer. - if (output !== undefined) { buffer.push(output); } - } - }, - - /** - Renders the view again. This will work regardless of whether the - view is already in the DOM or not. If the view is in the DOM, the - rendering process will be deferred to give bindings a chance - to synchronize. - - If children were added during the rendering process using `appendChild`, - `rerender` will remove them, because they will be added again - if needed by the next `render`. - - In general, if the display of your view changes, you should modify - the DOM element directly instead of manually calling `rerender`, which can - be slow. - - @method rerender - */ - rerender: function() { - return this.currentState.rerender(this); - }, - - /** - Iterates over the view's `classNameBindings` array, inserts the value - of the specified property into the `classNames` array, then creates an - observer to update the view's element if the bound property ever changes - in the future. - - @method _applyClassNameBindings - @private - */ - _applyClassNameBindings: function(classBindings) { - var classNames = this.classNames; - var elem, newClass, dasherizedClass; - - // Loop through all of the configured bindings. These will be either - // property names ('isUrgent') or property paths relative to the view - // ('content.isUrgent') - forEach(classBindings, function(binding) { - - var boundBinding; - if (isStream(binding)) { - boundBinding = binding; - } else { - boundBinding = streamifyClassNameBinding(this, binding, '_view.'); - } - - // Variable in which the old class value is saved. The observer function - // closes over this variable, so it knows which string to remove when - // the property changes. - var oldClass; - - // Set up an observer on the context. If the property changes, toggle the - // class name. - var observer = this._wrapAsScheduled(function() { - // Get the current value of the property - elem = this.$(); - newClass = read(boundBinding); - - // If we had previously added a class to the element, remove it. - if (oldClass) { - elem.removeClass(oldClass); - // Also remove from classNames so that if the view gets rerendered, - // the class doesn't get added back to the DOM. - classNames.removeObject(oldClass); - } - - // If necessary, add a new class. Make sure we keep track of it so - // it can be removed in the future. - if (newClass) { - elem.addClass(newClass); - oldClass = newClass; - } else { - oldClass = null; - } - }); - - // Get the class name for the property at its current value - dasherizedClass = read(boundBinding); - - if (dasherizedClass) { - // Ensure that it gets into the classNames array - // so it is displayed when we render. - addObject(classNames, dasherizedClass); - - // Save a reference to the class name so we can remove it - // if the observer fires. Remember that this variable has - // been closed over by the observer. - oldClass = dasherizedClass; - } - - subscribe(boundBinding, observer, this); - // Remove className so when the view is rerendered, - // the className is added based on binding reevaluation - this.one('willClearRender', function() { - if (oldClass) { - classNames.removeObject(oldClass); - oldClass = null; - } - }); - - }, this); - }, - - _unspecifiedAttributeBindings: null, - - /** - Iterates through the view's attribute bindings, sets up observers for each, - then applies the current value of the attributes to the passed render buffer. - - @method _applyAttributeBindings - @param {Ember.RenderBuffer} buffer - @private - */ - _applyAttributeBindings: function(buffer, attributeBindings) { - var attributeValue; - var unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {}; - - forEach(attributeBindings, function(binding) { - var split = binding.split(':'); - var property = split[0]; - var attributeName = split[1] || property; - - Ember.assert('You cannot use class as an attributeBinding, use classNameBindings instead.', attributeName !== 'class'); - - if (property in this) { - this._setupAttributeBindingObservation(property, attributeName); - - // Determine the current value and add it to the render buffer - // if necessary. - attributeValue = get(this, property); - View.applyAttributeBindings(buffer, attributeName, attributeValue); - } else { - unspecifiedAttributeBindings[property] = attributeName; - } - }, this); - - // Lazily setup setUnknownProperty after attributeBindings are initially applied - this.setUnknownProperty = this._setUnknownProperty; - }, - - _setupAttributeBindingObservation: function(property, attributeName) { - var attributeValue, elem; - - // Create an observer to add/remove/change the attribute if the - // JavaScript property changes. - var observer = function() { - elem = this.$(); - - attributeValue = get(this, property); - - var normalizedName = normalizeProperty(elem, attributeName.toLowerCase()) || attributeName; - View.applyAttributeBindings(elem, normalizedName, attributeValue); - }; - - this.registerObserver(this, property, observer); - }, - - /** - We're using setUnknownProperty as a hook to setup attributeBinding observers for - properties that aren't defined on a view at initialization time. - - Note: setUnknownProperty will only be called once for each property. - - @method setUnknownProperty - @param key - @param value - @private - */ - setUnknownProperty: null, // Gets defined after initialization by _applyAttributeBindings - - _setUnknownProperty: function(key, value) { - var attributeName = this._unspecifiedAttributeBindings && this._unspecifiedAttributeBindings[key]; - if (attributeName) { - this._setupAttributeBindingObservation(key, attributeName); - } - - defineProperty(this, key); - return set(this, key, value); - }, - - /** - Given a property name, returns a dasherized version of that - property name if the property evaluates to a non-falsy value. - - For example, if the view has property `isUrgent` that evaluates to true, - passing `isUrgent` to this method will return `"is-urgent"`. - - @method _classStringForProperty - @param property - @private - */ - _classStringForProperty: function(parsedPath) { - return View._classStringForValue(parsedPath.path, parsedPath.stream.value(), parsedPath.className, parsedPath.falsyClassName); - }, - - // .......................................................... - // ELEMENT SUPPORT - // - - /** - Returns the current DOM element for the view. - - @property element - @type DOMElement - */ - element: null, - - /** - Returns a jQuery object for this view's element. If you pass in a selector - string, this method will return a jQuery object, using the current element - as its buffer. - - For example, calling `view.$('li')` will return a jQuery object containing - all of the `li` elements inside the DOM element of this view. - - @method $ - @param {String} [selector] a jQuery-compatible selector string - @return {jQuery} the jQuery object for the DOM node - */ - $: function(sel) { - return this.currentState.$(this, sel); - }, - - mutateChildViews: function(callback) { - var childViews = this._childViews; - var idx = childViews.length; - var view; - - while(--idx >= 0) { - view = childViews[idx]; - callback(this, view, idx); - } - - return this; - }, - - forEachChildView: function(callback) { - var childViews = this._childViews; - - if (!childViews) { return this; } - - var len = childViews.length; - var view, idx; - - for (idx = 0; idx < len; idx++) { - view = childViews[idx]; - callback(view); - } - - return this; - }, - - /** - Appends the view's element to the specified parent element. - - If the view does not have an HTML representation yet, `createElement()` - will be called automatically. - - Note that this method just schedules the view to be appended; the DOM - element will not be appended to the given element until all bindings have - finished synchronizing. - - This is not typically a function that you will need to call directly when - building your application. You might consider using `Ember.ContainerView` - instead. If you do need to use `appendTo`, be sure that the target element - you are providing is associated with an `Ember.Application` and does not - have an ancestor element that is associated with an Ember view. - - @method appendTo - @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object - @return {Ember.View} receiver - */ - appendTo: function(selector) { - var target = jQuery(selector); - - Ember.assert("You tried to append to (" + selector + ") but that isn't in the DOM", target.length > 0); - Ember.assert("You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.", !target.is('.ember-view') && !target.parents().is('.ember-view')); - - this.constructor.renderer.appendTo(this, target[0]); - - return this; - }, - - /** - Replaces the content of the specified parent element with this view's - element. If the view does not have an HTML representation yet, - the element will be generated automatically. - - Note that this method just schedules the view to be appended; the DOM - element will not be appended to the given element until all bindings have - finished synchronizing - - @method replaceIn - @param {String|DOMElement|jQuery} target A selector, element, HTML string, or jQuery object - @return {Ember.View} received - */ - replaceIn: function(selector) { - var target = jQuery(selector); - - Ember.assert("You tried to replace in (" + selector + ") but that isn't in the DOM", target.length > 0); - Ember.assert("You cannot replace an existing Ember.View. Consider using Ember.ContainerView instead.", !target.is('.ember-view') && !target.parents().is('.ember-view')); - - this.constructor.renderer.replaceIn(this, target[0]); - - return this; - }, - - /** - Appends the view's element to the document body. If the view does - not have an HTML representation yet - the element will be generated automatically. - - If your application uses the `rootElement` property, you must append - the view within that element. Rendering views outside of the `rootElement` - is not supported. - - Note that this method just schedules the view to be appended; the DOM - element will not be appended to the document body until all bindings have - finished synchronizing. - - @method append - @return {Ember.View} receiver - */ - append: function() { - return this.appendTo(document.body); - }, - - /** - Removes the view's element from the element to which it is attached. - - @method remove - @return {Ember.View} receiver - */ - remove: function() { - // What we should really do here is wait until the end of the run loop - // to determine if the element has been re-appended to a different - // element. - // In the interim, we will just re-render if that happens. It is more - // important than elements get garbage collected. - if (!this.removedFromDOM) { this.destroyElement(); } - }, - - /** - The HTML `id` of the view's element in the DOM. You can provide this - value yourself but it must be unique (just as in HTML): - - ```handlebars - {{my-component elementId="a-really-cool-id"}} - ``` - - If not manually set a default value will be provided by the framework. - - Once rendered an element's `elementId` is considered immutable and you - should never change it. - - @property elementId - @type String - */ - elementId: null, - - /** - Attempts to discover the element in the parent element. The default - implementation looks for an element with an ID of `elementId` (or the - view's guid if `elementId` is null). You can override this method to - provide your own form of lookup. For example, if you want to discover your - element using a CSS class name instead of an ID. - - @method findElementInParentElement - @param {DOMElement} parentElement The parent's DOM element - @return {DOMElement} The discovered element - */ - findElementInParentElement: function(parentElem) { - var id = "#" + this.elementId; - return jQuery(id)[0] || jQuery(id, parentElem)[0]; - }, - - /** - Creates a DOM representation of the view and all of its child views by - recursively calling the `render()` method. - - After the element has been inserted into the DOM, `didInsertElement` will - be called on this view and all of its child views. - - @method createElement - @return {Ember.View} receiver - */ - createElement: function() { - if (this.element) { return this; } - - this._didCreateElementWithoutMorph = true; - this.constructor.renderer.renderTree(this); - - return this; - }, - - /** - Called when a view is going to insert an element into the DOM. - - @event willInsertElement - */ - willInsertElement: K, - - /** - Called when the element of the view has been inserted into the DOM - or after the view was re-rendered. Override this function to do any - set up that requires an element in the document body. - - When a view has children, didInsertElement will be called on the - child view(s) first, bubbling upwards through the hierarchy. - - @event didInsertElement - */ - didInsertElement: K, - - /** - Called when the view is about to rerender, but before anything has - been torn down. This is a good opportunity to tear down any manual - observers you have installed based on the DOM state - - @event willClearRender - */ - willClearRender: K, - - /** - Destroys any existing element along with the element for any child views - as well. If the view does not currently have a element, then this method - will do nothing. - - If you implement `willDestroyElement()` on your view, then this method will - be invoked on your view before your element is destroyed to give you a - chance to clean up any event handlers, etc. - - If you write a `willDestroyElement()` handler, you can assume that your - `didInsertElement()` handler was called earlier for the same element. - - You should not call or override this method yourself, but you may - want to implement the above callbacks. - - @method destroyElement - @return {Ember.View} receiver - */ - destroyElement: function() { - return this.currentState.destroyElement(this); - }, - - /** - Called when the element of the view is going to be destroyed. Override - this function to do any teardown that requires an element, like removing - event listeners. - - Please note: any property changes made during this event will have no - effect on object observers. - - @event willDestroyElement - */ - willDestroyElement: K, - - /** - Called when the parentView property has changed. - - @event parentViewDidChange - */ - parentViewDidChange: K, - - instrumentName: 'view', - - instrumentDetails: function(hash) { - hash.template = get(this, 'templateName'); - this._super(hash); - }, - - beforeRender: function(buffer) {}, - - afterRender: function(buffer) {}, - - applyAttributesToBuffer: function(buffer) { - // Creates observers for all registered class name and attribute bindings, - // then adds them to the element. - var classNameBindings = this.classNameBindings; - if (classNameBindings.length) { - this._applyClassNameBindings(classNameBindings); - } - - // Pass the render buffer so the method can apply attributes directly. - // This isn't needed for class name bindings because they use the - // existing classNames infrastructure. - var attributeBindings = this.attributeBindings; - if (attributeBindings.length) { - this._applyAttributeBindings(buffer, attributeBindings); - } - - buffer.setClasses(this.classNames); - buffer.id(this.elementId); - - var role = get(this, 'ariaRole'); - if (role) { - buffer.attr('role', role); - } - - if (get(this, 'isVisible') === false) { - buffer.style('display', 'none'); - } - }, - - // .......................................................... - // STANDARD RENDER PROPERTIES - // - - /** - Tag name for the view's outer element. The tag name is only used when an - element is first created. If you change the `tagName` for an element, you - must destroy and recreate the view element. - - By default, the render buffer will use a `
    ` tag for views. - - @property tagName - @type String - @default null - */ - - // We leave this null by default so we can tell the difference between - // the default case and a user-specified tag. - tagName: null, - - /** - The WAI-ARIA role of the control represented by this view. For example, a - button may have a role of type 'button', or a pane may have a role of - type 'alertdialog'. This property is used by assistive software to help - visually challenged users navigate rich web applications. - - The full list of valid WAI-ARIA roles is available at: - [http://www.w3.org/TR/wai-aria/roles#roles_categorization](http://www.w3.org/TR/wai-aria/roles#roles_categorization) - - @property ariaRole - @type String - @default null - */ - ariaRole: null, - - /** - Standard CSS class names to apply to the view's outer element. This - property automatically inherits any class names defined by the view's - superclasses as well. - - @property classNames - @type Array - @default ['ember-view'] - */ - classNames: ['ember-view'], - - /** - A list of properties of the view to apply as class names. If the property - is a string value, the value of that string will be applied as a class - name. - - ```javascript - // Applies the 'high' class to the view element - Ember.View.extend({ - classNameBindings: ['priority'] - priority: 'high' - }); - ``` - - If the value of the property is a Boolean, the name of that property is - added as a dasherized class name. - - ```javascript - // Applies the 'is-urgent' class to the view element - Ember.View.extend({ - classNameBindings: ['isUrgent'] - isUrgent: true - }); - ``` - - If you would prefer to use a custom value instead of the dasherized - property name, you can pass a binding like this: - - ```javascript - // Applies the 'urgent' class to the view element - Ember.View.extend({ - classNameBindings: ['isUrgent:urgent'] - isUrgent: true - }); - ``` - - This list of properties is inherited from the view's superclasses as well. - - @property classNameBindings - @type Array - @default [] - */ - classNameBindings: EMPTY_ARRAY, - - /** - A list of properties of the view to apply as attributes. If the property is - a string value, the value of that string will be applied as the attribute. - - ```javascript - // Applies the type attribute to the element - // with the value "button", like
    - Ember.View.extend({ - attributeBindings: ['type'], - type: 'button' - }); - ``` - - If the value of the property is a Boolean, the name of that property is - added as an attribute. - - ```javascript - // Renders something like
    - Ember.View.extend({ - attributeBindings: ['enabled'], - enabled: true - }); - ``` - - @property attributeBindings - */ - attributeBindings: EMPTY_ARRAY, - - // ....................................................... - // CORE DISPLAY METHODS - // - - /** - Setup a view, but do not finish waking it up. - - * configure `childViews` - * register the view with the global views hash, which is used for event - dispatch - - @method init - @private - */ - init: function() { - if (!this.isVirtual && !this.elementId) { - this.elementId = guidFor(this); - } - - this._super(); - - // setup child views. be sure to clone the child views array first - this._childViews = this._childViews.slice(); - this._baseContext = undefined; - this._contextStream = undefined; - this._streamBindings = undefined; - - if (!this._keywords) { - this._keywords = create(null); - } - this._keywords._view = this; - this._keywords.view = undefined; - this._keywords.controller = new KeyStream(this, 'controller'); - this._setupKeywords(); - - Ember.assert("Only arrays are allowed for 'classNameBindings'", typeOf(this.classNameBindings) === 'array'); - this.classNameBindings = emberA(this.classNameBindings.slice()); - - Ember.assert("Only arrays of static class strings are allowed for 'classNames'. For dynamic classes, use 'classNameBindings'.", typeOf(this.classNames) === 'array'); - this.classNames = emberA(this.classNames.slice()); - }, - - appendChild: function(view, options) { - return this.currentState.appendChild(this, view, options); - }, - - /** - Removes the child view from the parent view. - - @method removeChild - @param {Ember.View} view - @return {Ember.View} receiver - */ - removeChild: function(view) { - // If we're destroying, the entire subtree will be - // freed, and the DOM will be handled separately, - // so no need to mess with childViews. - if (this.isDestroying) { return; } - - // update parent node - set(view, '_parentView', null); - - // remove view from childViews array. - var childViews = this._childViews; - - removeObject(childViews, view); - - this.propertyDidChange('childViews'); // HUH?! what happened to will change? - - return this; - }, - - /** - Removes all children from the `parentView`. - - @method removeAllChildren - @return {Ember.View} receiver - */ - removeAllChildren: function() { - return this.mutateChildViews(function(parentView, view) { - parentView.removeChild(view); - }); - }, - - destroyAllChildren: function() { - return this.mutateChildViews(function(parentView, view) { - view.destroy(); - }); - }, - - /** - Removes the view from its `parentView`, if one is found. Otherwise - does nothing. - - @method removeFromParent - @return {Ember.View} receiver - */ - removeFromParent: function() { - var parent = this._parentView; - - // Remove DOM element from parent - this.remove(); - - if (parent) { parent.removeChild(this); } - return this; - }, - - /** - You must call `destroy` on a view to destroy the view (and all of its - child views). This will remove the view from any parent node, then make - sure that the DOM element managed by the view can be released by the - memory manager. - - @method destroy - */ - destroy: function() { - // get parentView before calling super because it'll be destroyed - var nonVirtualParentView = get(this, 'parentView'); - var viewName = this.viewName; - - if (!this._super()) { return; } - - // remove from non-virtual parent view if viewName was specified - if (viewName && nonVirtualParentView) { - nonVirtualParentView.set(viewName, null); - } - - return this; - }, - - /** - Instantiates a view to be added to the childViews array during view - initialization. You generally will not call this method directly unless - you are overriding `createChildViews()`. Note that this method will - automatically configure the correct settings on the new view instance to - act as a child of the parent. - - @method createChildView - @param {Class|String} viewClass - @param {Hash} [attrs] Attributes to add - @return {Ember.View} new instance - */ - createChildView: function(view, attrs) { - if (!view) { - throw new TypeError("createChildViews first argument must exist"); - } - - if (view.isView && view._parentView === this && view.container === this.container) { - return view; - } - - attrs = attrs || {}; - attrs._parentView = this; - - if (CoreView.detect(view)) { - attrs.container = this.container; - view = view.create(attrs); - - // don't set the property on a virtual view, as they are invisible to - // consumers of the view API - if (view.viewName) { - set(get(this, 'concreteView'), view.viewName, view); - } - } else if ('string' === typeof view) { - var fullName = 'view:' + view; - var ViewKlass = this.container.lookupFactory(fullName); - - Ember.assert("Could not find view: '" + fullName + "'", !!ViewKlass); - - view = ViewKlass.create(attrs); - } else { - Ember.assert('You must pass instance or subclass of View', view.isView); - - attrs.container = this.container; - setProperties(view, attrs); - } - - return view; - }, - - becameVisible: K, - becameHidden: K, - - /** - When the view's `isVisible` property changes, toggle the visibility - element of the actual DOM element. - - @method _isVisibleDidChange - @private - */ - _isVisibleDidChange: observer('isVisible', function() { - if (this._isVisible === get(this, 'isVisible')) { return ; } - run.scheduleOnce('render', this, this._toggleVisibility); - }), - - _toggleVisibility: function() { - var $el = this.$(); - var isVisible = get(this, 'isVisible'); - - if (this._isVisible === isVisible) { return ; } - - // It's important to keep these in sync, even if we don't yet have - // an element in the DOM to manipulate: - this._isVisible = isVisible; - - if (!$el) { return; } - - $el.toggle(isVisible); - - if (this._isAncestorHidden()) { return; } - - if (isVisible) { - this._notifyBecameVisible(); - } else { - this._notifyBecameHidden(); - } - }, - - _notifyBecameVisible: function() { - this.trigger('becameVisible'); - - this.forEachChildView(function(view) { - var isVisible = get(view, 'isVisible'); - - if (isVisible || isVisible === null) { - view._notifyBecameVisible(); - } - }); - }, - - _notifyBecameHidden: function() { - this.trigger('becameHidden'); - this.forEachChildView(function(view) { - var isVisible = get(view, 'isVisible'); - - if (isVisible || isVisible === null) { - view._notifyBecameHidden(); - } - }); - }, - - _isAncestorHidden: function() { - var parent = get(this, 'parentView'); - - while (parent) { - if (get(parent, 'isVisible') === false) { return true; } - - parent = get(parent, 'parentView'); - } - - return false; - }, - transitionTo: function(state, children) { - Ember.deprecate("Ember.View#transitionTo has been deprecated, it is for internal use only"); - this._transitionTo(state, children); - }, - _transitionTo: function(state, children) { - var priorState = this.currentState; - var currentState = this.currentState = this._states[state]; - this._state = state; - - if (priorState && priorState.exit) { priorState.exit(this); } - if (currentState.enter) { currentState.enter(this); } - }, - - // ....................................................... - // EVENT HANDLING - // - - /** - Handle events from `Ember.EventDispatcher` - - @method handleEvent - @param eventName {String} - @param evt {Event} - @private - */ - handleEvent: function(eventName, evt) { - return this.currentState.handleEvent(this, eventName, evt); - }, - - registerObserver: function(root, path, target, observer) { - if (!observer && 'function' === typeof target) { - observer = target; - target = null; - } - - if (!root || typeof root !== 'object') { - return; - } - - var scheduledObserver = this._wrapAsScheduled(observer); - - addObserver(root, path, target, scheduledObserver); - - this.one('willClearRender', function() { - removeObserver(root, path, target, scheduledObserver); - }); - }, - - _wrapAsScheduled: function(fn) { - var view = this; - var stateCheckedFn = function() { - view.currentState.invokeObserver(this, fn); - }; - var scheduledFn = function() { - run.scheduleOnce('render', this, stateCheckedFn); - }; - return scheduledFn; - }, - - getStream: function(path) { - var stream = this._getContextStream().get(path); - - stream._label = path; - - return stream; - }, - - _getBindingForStream: function(pathOrStream) { - if (this._streamBindings === undefined) { - this._streamBindings = create(null); - this.one('willDestroyElement', this, this._destroyStreamBindings); - } - - var path = pathOrStream; - if (isStream(pathOrStream)) { - path = pathOrStream._label; - - if (!path) { - // if no _label is present on the provided stream - // it is likely a subexpr and cannot be set (so it - // does not need a StreamBinding) - return pathOrStream; - } - } - - if (this._streamBindings[path] !== undefined) { - return this._streamBindings[path]; - } else { - var stream = this._getContextStream().get(path); - var streamBinding = new StreamBinding(stream); - - streamBinding._label = path; - - return this._streamBindings[path] = streamBinding; - } - }, - - _destroyStreamBindings: function() { - var streamBindings = this._streamBindings; - for (var path in streamBindings) { - streamBindings[path].destroy(); - } - this._streamBindings = undefined; - }, - - _getContextStream: function() { - if (this._contextStream === undefined) { - this._baseContext = new KeyStream(this, 'context'); - this._contextStream = new ContextStream(this); - this.one('willDestroyElement', this, this._destroyContextStream); - } - - return this._contextStream; - }, - - _destroyContextStream: function() { - this._baseContext.destroy(); - this._baseContext = undefined; - this._contextStream.destroy(); - this._contextStream = undefined; - }, - - _unsubscribeFromStreamBindings: function() { - for (var key in this._streamBindingSubscriptions) { - var streamBinding = this[key + 'Binding']; - var callback = this._streamBindingSubscriptions[key]; - streamBinding.unsubscribe(callback); - } - } - }); - - deprecateProperty(View.prototype, 'state', '_state'); - deprecateProperty(View.prototype, 'states', '_states'); - - /* - Describe how the specified actions should behave in the various - states that a view can exist in. Possible states: - - * preRender: when a view is first instantiated, and after its - element was destroyed, it is in the preRender state - * inBuffer: once a view has been rendered, but before it has - been inserted into the DOM, it is in the inBuffer state - * hasElement: the DOM representation of the view is created, - and is ready to be inserted - * inDOM: once a view has been inserted into the DOM it is in - the inDOM state. A view spends the vast majority of its - existence in this state. - * destroyed: once a view has been destroyed (using the destroy - method), it is in this state. No further actions can be invoked - on a destroyed view. - */ - - // in the destroyed state, everything is illegal - - // before rendering has begun, all legal manipulations are noops. - - // inside the buffer, legal manipulations are done on the buffer - - // once the view has been inserted into the DOM, legal manipulations - // are done on the DOM element. - - var mutation = EmberObject.extend(Evented).create(); - // TODO MOVE TO RENDERER HOOKS - View.addMutationListener = function(callback) { - mutation.on('change', callback); - }; - - View.removeMutationListener = function(callback) { - mutation.off('change', callback); - }; - - View.notifyMutationListeners = function() { - mutation.trigger('change'); - }; - - /** - Global views hash - - @property views - @static - @type Hash - */ - View.views = {}; - - // If someone overrides the child views computed property when - // defining their class, we want to be able to process the user's - // supplied childViews and then restore the original computed property - // at view initialization time. This happens in Ember.ContainerView's init - // method. - View.childViewsProperty = childViewsProperty; - - // Used by Handlebars helpers, view element attributes - View.applyAttributeBindings = function(elem, name, initialValue) { - var value = sanitizeAttributeValue(elem[0], name, initialValue); - var type = typeOf(value); - - // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js - if (name !== 'value' && (type === 'string' || (type === 'number' && !isNaN(value)))) { - if (value !== elem.attr(name)) { - elem.attr(name, value); - } - } else if (name === 'value' || type === 'boolean') { - if (isNone(value) || value === false) { - // `null`, `undefined` or `false` should remove attribute - elem.removeAttr(name); - // In IE8 `prop` couldn't remove attribute when name is `required`. - if (name === 'required') { - elem.removeProp(name); - } else { - elem.prop(name, ''); - } - } else if (value !== elem.prop(name)) { - // value should always be properties - elem.prop(name, value); - } - } else if (!value) { - elem.removeAttr(name); - } - }; - - __exports__["default"] = View; - }); -enifed("ember-views/views/with_view", - ["ember-metal/property_set","ember-metal/utils","ember-views/views/bound_view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - - /** - @module ember - @submodule ember-views - */ - - var set = __dependency1__.set; - var apply = __dependency2__.apply; - var BoundView = __dependency3__["default"]; - - __exports__["default"] = BoundView.extend({ - init: function() { - apply(this, this._super, arguments); - - var controllerName = this.templateHash.controller; - - if (controllerName) { - var previousContext = this.previousContext; - var controller = this.container.lookupFactory('controller:'+controllerName).create({ - parentController: previousContext, - target: previousContext - }); - - this._generatedController = controller; - - if (this.preserveContext) { - this._blockArguments = [ controller ]; - this.lazyValue.subscribe(function(modelStream) { - set(controller, 'model', modelStream.value()); - }); - } else { - set(this, 'controller', controller); - this.valueNormalizerFunc = function(result) { - controller.set('model', result); - return controller; - }; - } - - set(controller, 'model', this.lazyValue.value()); - } else { - if (this.preserveContext) { - this._blockArguments = [ this.lazyValue ]; - } - } - }, - - willDestroy: function() { - this._super(); - - if (this._generatedController) { - this._generatedController.destroy(); - } - } - }); - }); -enifed("ember", - ["ember-metal","ember-runtime","ember-views","ember-routing","ember-application","ember-extension-support","ember-htmlbars","ember-routing-htmlbars","ember-runtime/system/lazy_load"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__) { - "use strict"; - /* global navigator */ - // require the main entry points for each of these packages - // this is so that the global exports occur properly - - var runLoadHooks = __dependency9__.runLoadHooks; - - if (Ember.__loader.registry['ember-template-compiler']) { - requireModule('ember-template-compiler'); - } - - // do this to ensure that Ember.Test is defined properly on the global - // if it is present. - if (Ember.__loader.registry['ember-testing']) { - requireModule('ember-testing'); - } - - runLoadHooks('Ember'); - - /** - Ember - - @module ember - */ - - Ember.deprecate('Usage of Ember is deprecated for Internet Explorer 6 and 7, support will be removed in the next major version.', !navigator.userAgent.match(/MSIE [67]/)); - }); -enifed("htmlbars-util", - ["./htmlbars-util/safe-string","./htmlbars-util/handlebars/utils","./htmlbars-util/namespaces","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var SafeString = __dependency1__["default"]; - var escapeExpression = __dependency2__.escapeExpression; - var getAttrNamespace = __dependency3__.getAttrNamespace; - - __exports__.SafeString = SafeString; - __exports__.escapeExpression = escapeExpression; - __exports__.getAttrNamespace = getAttrNamespace; - }); -enifed("htmlbars-util/array-utils", - ["exports"], - function(__exports__) { - "use strict"; - function forEach(array, callback, binding) { - var i, l; - if (binding === undefined) { - for (i = 0, l = array.length; i < l; i++) { - callback(array[i], i, array); - } - } else { - for (i = 0, l = array.length; i < l; i++) { - callback.call(binding, array[i], i, array); - } - } - } - - __exports__.forEach = forEach;function map(array, callback) { - var output = []; - var i, l; - - for (i = 0, l = array.length; i < l; i++) { - output.push(callback(array[i], i, array)); - } - - return output; - } - - __exports__.map = map;var getIdx; - if (Array.prototype.indexOf) { - getIdx = function(array, obj, from){ - return array.indexOf(obj, from); - }; - } else { - getIdx = function(array, obj, from) { - if (from === undefined || from === null) { - from = 0; - } else if (from < 0) { - from = Math.max(0, array.length + from); - } - for (var i = from, l= array.length; i < l; i++) { - if (array[i] === obj) { - return i; - } - } - return -1; - }; - } - - var indexOfArray = getIdx; - __exports__.indexOfArray = indexOfArray; - }); -enifed("htmlbars-util/handlebars/safe-string", - ["exports"], - function(__exports__) { - "use strict"; - // Build out our basic SafeString type - function SafeString(string) { - this.string = string; - } - - SafeString.prototype.toString = SafeString.prototype.toHTML = function() { - return "" + this.string; - }; - - __exports__["default"] = SafeString; - }); -enifed("htmlbars-util/handlebars/utils", - ["./safe-string","exports"], - function(__dependency1__, __exports__) { - "use strict"; - /*jshint -W004 */ - var SafeString = __dependency1__["default"]; - - var escape = { - "&": "&", - "<": "<", - ">": ">", - '"': """, - "'": "'", - "`": "`" - }; - - var badChars = /[&<>"'`]/g; - var possible = /[&<>"'`]/; - - function escapeChar(chr) { - return escape[chr]; - } - - function extend(obj /* , ...source */) { - for (var i = 1; i < arguments.length; i++) { - for (var key in arguments[i]) { - if (Object.prototype.hasOwnProperty.call(arguments[i], key)) { - obj[key] = arguments[i][key]; - } - } - } - - return obj; - } - - __exports__.extend = extend;var toString = Object.prototype.toString; - __exports__.toString = toString; - // Sourced from lodash - // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt - var isFunction = function(value) { - return typeof value === 'function'; - }; - // fallback for older versions of Chrome and Safari - /* istanbul ignore next */ - if (isFunction(/x/)) { - isFunction = function(value) { - return typeof value === 'function' && toString.call(value) === '[object Function]'; - }; - } - var isFunction; - __exports__.isFunction = isFunction; - /* istanbul ignore next */ - var isArray = Array.isArray || function(value) { - return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false; - }; - __exports__.isArray = isArray; - - function escapeExpression(string) { - // don't escape SafeStrings, since they're already safe - if (string && string.toHTML) { - return string.toHTML(); - } else if (string == null) { - return ""; - } else if (!string) { - return string + ''; - } - - // Force a string conversion as this will be done by the append regardless and - // the regex test will do this transparently behind the scenes, causing issues if - // an object's to string has escaped characters in it. - string = "" + string; - - if(!possible.test(string)) { return string; } - return string.replace(badChars, escapeChar); - } - - __exports__.escapeExpression = escapeExpression;function isEmpty(value) { - if (!value && value !== 0) { - return true; - } else if (isArray(value) && value.length === 0) { - return true; - } else { - return false; - } - } - - __exports__.isEmpty = isEmpty;function appendContextPath(contextPath, id) { - return (contextPath ? contextPath + '.' : '') + id; - } - - __exports__.appendContextPath = appendContextPath; - }); -enifed("htmlbars-util/namespaces", - ["exports"], - function(__exports__) { - "use strict"; - // ref http://dev.w3.org/html5/spec-LC/namespaces.html - var defaultNamespaces = { - html: 'http://www.w3.org/1999/xhtml', - mathml: 'http://www.w3.org/1998/Math/MathML', - svg: 'http://www.w3.org/2000/svg', - xlink: 'http://www.w3.org/1999/xlink', - xml: 'http://www.w3.org/XML/1998/namespace' - }; - - function getAttrNamespace(attrName) { - var namespace; - - var colonIndex = attrName.indexOf(':'); - if (colonIndex !== -1) { - var prefix = attrName.slice(0, colonIndex); - namespace = defaultNamespaces[prefix]; - } - - return namespace || null; - } - - __exports__.getAttrNamespace = getAttrNamespace; - }); -enifed("htmlbars-util/object-utils", - ["exports"], - function(__exports__) { - "use strict"; - function merge(options, defaults) { - for (var prop in defaults) { - if (options.hasOwnProperty(prop)) { continue; } - options[prop] = defaults[prop]; - } - return options; - } - - __exports__.merge = merge; - }); -enifed("htmlbars-util/quoting", - ["exports"], - function(__exports__) { - "use strict"; - function escapeString(str) { - str = str.replace(/\\/g, "\\\\"); - str = str.replace(/"/g, '\\"'); - str = str.replace(/\n/g, "\\n"); - return str; - } - - __exports__.escapeString = escapeString; - - function string(str) { - return '"' + escapeString(str) + '"'; - } - - __exports__.string = string; - - function array(a) { - return "[" + a + "]"; - } - - __exports__.array = array; - - function hash(pairs) { - return "{" + pairs.join(", ") + "}"; - } - - __exports__.hash = hash;function repeat(chars, times) { - var str = ""; - while (times--) { - str += chars; - } - return str; - } - - __exports__.repeat = repeat; - }); -enifed("htmlbars-util/safe-string", - ["./handlebars/safe-string","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var SafeString = __dependency1__["default"]; - - __exports__["default"] = SafeString; - }); -enifed("morph", - ["./morph/morph","./morph/attr-morph","./morph/dom-helper","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Morph = __dependency1__["default"]; - var AttrMorph = __dependency2__["default"]; - var DOMHelper = __dependency3__["default"]; - - __exports__.Morph = Morph; - __exports__.AttrMorph = AttrMorph; - __exports__.DOMHelper = DOMHelper; - }); -enifed("morph/attr-morph", - ["./attr-morph/sanitize-attribute-value","./dom-helper/prop","./dom-helper/build-html-dom","../htmlbars-util","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var sanitizeAttributeValue = __dependency1__.sanitizeAttributeValue; - var isAttrRemovalValue = __dependency2__.isAttrRemovalValue; - var normalizeProperty = __dependency2__.normalizeProperty; - var svgNamespace = __dependency3__.svgNamespace; - var getAttrNamespace = __dependency4__.getAttrNamespace; - - function updateProperty(value) { - this.domHelper.setPropertyStrict(this.element, this.attrName, value); - } - - function updateAttribute(value) { - if (isAttrRemovalValue(value)) { - this.domHelper.removeAttribute(this.element, this.attrName); - } else { - this.domHelper.setAttribute(this.element, this.attrName, value); - } - } - - function updateAttributeNS(value) { - if (isAttrRemovalValue(value)) { - this.domHelper.removeAttribute(this.element, this.attrName); - } else { - this.domHelper.setAttributeNS(this.element, this.namespace, this.attrName, value); - } - } - - function AttrMorph(element, attrName, domHelper, namespace) { - this.element = element; - this.domHelper = domHelper; - this.namespace = namespace !== undefined ? namespace : getAttrNamespace(attrName); - this.escaped = true; - - var normalizedAttrName = normalizeProperty(this.element, attrName); - if (this.namespace) { - this._update = updateAttributeNS; - this.attrName = attrName; - } else { - if (element.namespaceURI === svgNamespace || attrName === 'style' || !normalizedAttrName) { - this.attrName = attrName; - this._update = updateAttribute; - } else { - this.attrName = normalizedAttrName; - this._update = updateProperty; - } - } - } - - AttrMorph.prototype.setContent = function (value) { - if (this.escaped) { - var sanitized = sanitizeAttributeValue(this.element, this.attrName, value); - this._update(sanitized, this.namespace); - } else { - this._update(value, this.namespace); - } - }; - - __exports__["default"] = AttrMorph; - }); -enifed("morph/attr-morph/sanitize-attribute-value", - ["exports"], - function(__exports__) { - "use strict"; - /* jshint scripturl:true */ - - var parsingNode; - var badProtocols = { - 'javascript:': true, - 'vbscript:': true - }; - - var badTags = { - 'A': true, - 'BODY': true, - 'LINK': true, - 'IMG': true, - 'IFRAME': true - }; - - var badAttributes = { - 'href': true, - 'src': true, - 'background': true - }; - __exports__.badAttributes = badAttributes; - function sanitizeAttributeValue(element, attribute, value) { - var tagName; - - if (!parsingNode) { - parsingNode = document.createElement('a'); - } - - if (!element) { - tagName = null; - } else { - tagName = element.tagName; - } - - if (value && value.toHTML) { - return value.toHTML(); - } - - if ((tagName === null || badTags[tagName]) && badAttributes[attribute]) { - parsingNode.href = value; - - if (badProtocols[parsingNode.protocol] === true) { - return 'unsafe:' + value; - } - } - - return value; - } - - __exports__.sanitizeAttributeValue = sanitizeAttributeValue; - }); -enifed("morph/dom-helper", - ["../morph/morph","../morph/attr-morph","./dom-helper/build-html-dom","./dom-helper/classes","./dom-helper/prop","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - var Morph = __dependency1__["default"]; - var AttrMorph = __dependency2__["default"]; - var buildHTMLDOM = __dependency3__.buildHTMLDOM; - var svgNamespace = __dependency3__.svgNamespace; - var svgHTMLIntegrationPoints = __dependency3__.svgHTMLIntegrationPoints; - var addClasses = __dependency4__.addClasses; - var removeClasses = __dependency4__.removeClasses; - var normalizeProperty = __dependency5__.normalizeProperty; - var isAttrRemovalValue = __dependency5__.isAttrRemovalValue; - - var doc = typeof document === 'undefined' ? false : document; - - var deletesBlankTextNodes = doc && (function(document){ - var element = document.createElement('div'); - element.appendChild( document.createTextNode('') ); - var clonedElement = element.cloneNode(true); - return clonedElement.childNodes.length === 0; - })(doc); - - var ignoresCheckedAttribute = doc && (function(document){ - var element = document.createElement('input'); - element.setAttribute('checked', 'checked'); - var clonedElement = element.cloneNode(false); - return !clonedElement.checked; - })(doc); - - var canRemoveSvgViewBoxAttribute = doc && (doc.createElementNS ? (function(document){ - var element = document.createElementNS(svgNamespace, 'svg'); - element.setAttribute('viewBox', '0 0 100 100'); - element.removeAttribute('viewBox'); - return !element.getAttribute('viewBox'); - })(doc) : true); - - var canClone = doc && (function(document){ - var element = document.createElement('div'); - element.appendChild( document.createTextNode(' ')); - element.appendChild( document.createTextNode(' ')); - var clonedElement = element.cloneNode(true); - return clonedElement.childNodes[0].nodeValue === ' '; - })(doc); - - // This is not the namespace of the element, but of - // the elements inside that elements. - function interiorNamespace(element){ - if ( - element && - element.namespaceURI === svgNamespace && - !svgHTMLIntegrationPoints[element.tagName] - ) { - return svgNamespace; - } else { - return null; - } - } - - // The HTML spec allows for "omitted start tags". These tags are optional - // when their intended child is the first thing in the parent tag. For - // example, this is a tbody start tag: - // - //
    - // - // - // - // The tbody may be omitted, and the browser will accept and render: - // - //
    - // - // - // However, the omitted start tag will still be added to the DOM. Here - // we test the string and context to see if the browser is about to - // perform this cleanup. - // - // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags - // describes which tags are omittable. The spec for tbody and colgroup - // explains this behavior: - // - // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element - // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element - // - - var omittedStartTagChildTest = /<([\w:]+)/; - function detectOmittedStartTag(string, contextualElement){ - // Omitted start tags are only inside table tags. - if (contextualElement.tagName === 'TABLE') { - var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string); - if (omittedStartTagChildMatch) { - var omittedStartTagChild = omittedStartTagChildMatch[1]; - // It is already asserted that the contextual element is a table - // and not the proper start tag. Just see if a tag was omitted. - return omittedStartTagChild === 'tr' || - omittedStartTagChild === 'col'; - } - } - } - - function buildSVGDOM(html, dom){ - var div = dom.document.createElement('div'); - div.innerHTML = ''+html+''; - return div.firstChild.childNodes; - } - - /* - * A class wrapping DOM functions to address environment compatibility, - * namespaces, contextual elements for morph un-escaped content - * insertion. - * - * When entering a template, a DOMHelper should be passed: - * - * template(context, { hooks: hooks, dom: new DOMHelper() }); - * - * TODO: support foreignObject as a passed contextual element. It has - * a namespace (svg) that does not match its internal namespace - * (xhtml). - * - * @class DOMHelper - * @constructor - * @param {HTMLDocument} _document The document DOM methods are proxied to - */ - function DOMHelper(_document){ - this.document = _document || document; - if (!this.document) { - throw new Error("A document object must be passed to the DOMHelper, or available on the global scope"); - } - this.canClone = canClone; - this.namespace = null; - } - - var prototype = DOMHelper.prototype; - prototype.constructor = DOMHelper; - - prototype.getElementById = function(id, rootNode) { - rootNode = rootNode || this.document; - return rootNode.getElementById(id); - }; - - prototype.insertBefore = function(element, childElement, referenceChild) { - return element.insertBefore(childElement, referenceChild); - }; - - prototype.appendChild = function(element, childElement) { - return element.appendChild(childElement); - }; - - prototype.childAt = function(element, indices) { - var child = element; - - for (var i = 0; i < indices.length; i++) { - child = child.childNodes.item(indices[i]); - } - - return child; - }; - - // Note to a Fellow Implementor: - // Ahh, accessing a child node at an index. Seems like it should be so simple, - // doesn't it? Unfortunately, this particular method has caused us a surprising - // amount of pain. As you'll note below, this method has been modified to walk - // the linked list of child nodes rather than access the child by index - // directly, even though there are two (2) APIs in the DOM that do this for us. - // If you're thinking to yourself, "What an oversight! What an opportunity to - // optimize this code!" then to you I say: stop! For I have a tale to tell. - // - // First, this code must be compatible with simple-dom for rendering on the - // server where there is no real DOM. Previously, we accessed a child node - // directly via `element.childNodes[index]`. While we *could* in theory do a - // full-fidelity simulation of a live `childNodes` array, this is slow, - // complicated and error-prone. - // - // "No problem," we thought, "we'll just use the similar - // `childNodes.item(index)` API." Then, we could just implement our own `item` - // method in simple-dom and walk the child node linked list there, allowing - // us to retain the performance advantages of the (surely optimized) `item()` - // API in the browser. - // - // Unfortunately, an enterprising soul named Samy Alzahrani discovered that in - // IE8, accessing an item out-of-bounds via `item()` causes an exception where - // other browsers return null. This necessitated a... check of - // `childNodes.length`, bringing us back around to having to support a - // full-fidelity `childNodes` array! - // - // Worst of all, Kris Selden investigated how browsers are actualy implemented - // and discovered that they're all linked lists under the hood anyway. Accessing - // `childNodes` requires them to allocate a new live collection backed by that - // linked list, which is itself a rather expensive operation. Our assumed - // optimization had backfired! That is the danger of magical thinking about - // the performance of native implementations. - // - // And this, my friends, is why the following implementation just walks the - // linked list, as surprised as that may make you. Please ensure you understand - // the above before changing this and submitting a PR. - // - // Tom Dale, January 18th, 2015, Portland OR - prototype.childAtIndex = function(element, index) { - var node = element.firstChild; - - for (var idx = 0; node && idx < index; idx++) { - node = node.nextSibling; - } - - return node; - }; - - prototype.appendText = function(element, text) { - return element.appendChild(this.document.createTextNode(text)); - }; - - prototype.setAttribute = function(element, name, value) { - element.setAttribute(name, String(value)); - }; - - prototype.setAttributeNS = function(element, namespace, name, value) { - element.setAttributeNS(namespace, name, String(value)); - }; - - if (canRemoveSvgViewBoxAttribute){ - prototype.removeAttribute = function(element, name) { - element.removeAttribute(name); - }; - } else { - prototype.removeAttribute = function(element, name) { - if (element.tagName === 'svg' && name === 'viewBox') { - element.setAttribute(name, null); - } else { - element.removeAttribute(name); - } - }; - } - - prototype.setPropertyStrict = function(element, name, value) { - element[name] = value; - }; - - prototype.setProperty = function(element, name, value, namespace) { - var lowercaseName = name.toLowerCase(); - if (element.namespaceURI === svgNamespace || lowercaseName === 'style') { - if (isAttrRemovalValue(value)) { - element.removeAttribute(name); - } else { - if (namespace) { - element.setAttributeNS(namespace, name, value); - } else { - element.setAttribute(name, value); - } - } - } else { - var normalized = normalizeProperty(element, name); - if (normalized) { - element[normalized] = value; - } else { - if (isAttrRemovalValue(value)) { - element.removeAttribute(name); - } else { - if (namespace && element.setAttributeNS) { - element.setAttributeNS(namespace, name, value); - } else { - element.setAttribute(name, value); - } - } - } - } - }; - - if (doc && doc.createElementNS) { - // Only opt into namespace detection if a contextualElement - // is passed. - prototype.createElement = function(tagName, contextualElement) { - var namespace = this.namespace; - if (contextualElement) { - if (tagName === 'svg') { - namespace = svgNamespace; - } else { - namespace = interiorNamespace(contextualElement); - } - } - if (namespace) { - return this.document.createElementNS(namespace, tagName); - } else { - return this.document.createElement(tagName); - } - }; - prototype.setAttributeNS = function(element, namespace, name, value) { - element.setAttributeNS(namespace, name, String(value)); - }; - } else { - prototype.createElement = function(tagName) { - return this.document.createElement(tagName); - }; - prototype.setAttributeNS = function(element, namespace, name, value) { - element.setAttribute(name, String(value)); - }; - } - - prototype.addClasses = addClasses; - prototype.removeClasses = removeClasses; - - prototype.setNamespace = function(ns) { - this.namespace = ns; - }; - - prototype.detectNamespace = function(element) { - this.namespace = interiorNamespace(element); - }; - - prototype.createDocumentFragment = function(){ - return this.document.createDocumentFragment(); - }; - - prototype.createTextNode = function(text){ - return this.document.createTextNode(text); - }; - - prototype.createComment = function(text){ - return this.document.createComment(text); - }; - - prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){ - if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { - for (var i=0, len=blankChildTextNodes.length;i]*selected/; - return function detectAutoSelectedOption(select, option, html) { //jshint ignore:line - return select.selectedIndex === 0 && - !detectAutoSelectedOptionRegex.test(html); - }; - })(); - } else { - detectAutoSelectedOption = function detectAutoSelectedOption(select, option, html) { //jshint ignore:line - var selectedAttribute = option.getAttribute('selected'); - return select.selectedIndex === 0 && ( - selectedAttribute === null || - ( selectedAttribute !== '' && selectedAttribute.toLowerCase() !== 'selected' ) - ); - }; - } - - var tagNamesRequiringInnerHTMLFix = doc && (function(document) { - var tagNamesRequiringInnerHTMLFix; - // IE 9 and earlier don't allow us to set innerHTML on col, colgroup, frameset, - // html, style, table, tbody, tfoot, thead, title, tr. Detect this and add - // them to an initial list of corrected tags. - // - // Here we are only dealing with the ones which can have child nodes. - // - var tableNeedsInnerHTMLFix; - var tableInnerHTMLTestElement = document.createElement('table'); - try { - tableInnerHTMLTestElement.innerHTML = ''; - } catch (e) { - } finally { - tableNeedsInnerHTMLFix = (tableInnerHTMLTestElement.childNodes.length === 0); - } - if (tableNeedsInnerHTMLFix) { - tagNamesRequiringInnerHTMLFix = { - colgroup: ['table'], - table: [], - tbody: ['table'], - tfoot: ['table'], - thead: ['table'], - tr: ['table', 'tbody'] - }; - } - - // IE 8 doesn't allow setting innerHTML on a select tag. Detect this and - // add it to the list of corrected tags. - // - var selectInnerHTMLTestElement = document.createElement('select'); - selectInnerHTMLTestElement.innerHTML = ''; - if (!selectInnerHTMLTestElement.childNodes[0]) { - tagNamesRequiringInnerHTMLFix = tagNamesRequiringInnerHTMLFix || {}; - tagNamesRequiringInnerHTMLFix.select = []; - } - return tagNamesRequiringInnerHTMLFix; - })(doc); - - function scriptSafeInnerHTML(element, html) { - // without a leading text node, IE will drop a leading script tag. - html = '­'+html; - - element.innerHTML = html; - - var nodes = element.childNodes; - - // Look for ­ to remove it. - var shyElement = nodes[0]; - while (shyElement.nodeType === 1 && !shyElement.nodeName) { - shyElement = shyElement.firstChild; - } - // At this point it's the actual unicode character. - if (shyElement.nodeType === 3 && shyElement.nodeValue.charAt(0) === "\u00AD") { - var newValue = shyElement.nodeValue.slice(1); - if (newValue.length) { - shyElement.nodeValue = shyElement.nodeValue.slice(1); - } else { - shyElement.parentNode.removeChild(shyElement); - } - } - - return nodes; - } - - function buildDOMWithFix(html, contextualElement){ - var tagName = contextualElement.tagName; - - // Firefox versions < 11 do not have support for element.outerHTML. - var outerHTML = contextualElement.outerHTML || new XMLSerializer().serializeToString(contextualElement); - if (!outerHTML) { - throw "Can't set innerHTML on "+tagName+" in this browser"; - } - - var wrappingTags = tagNamesRequiringInnerHTMLFix[tagName.toLowerCase()]; - var startTag = outerHTML.match(new RegExp("<"+tagName+"([^>]*)>", 'i'))[0]; - var endTag = ''; - - var wrappedHTML = [startTag, html, endTag]; - - var i = wrappingTags.length; - var wrappedDepth = 1 + i; - while(i--) { - wrappedHTML.unshift('<'+wrappingTags[i]+'>'); - wrappedHTML.push(''); - } - - var wrapper = document.createElement('div'); - scriptSafeInnerHTML(wrapper, wrappedHTML.join('')); - var element = wrapper; - while (wrappedDepth--) { - element = element.firstChild; - while (element && element.nodeType !== 1) { - element = element.nextSibling; - } - } - while (element && element.tagName !== tagName) { - element = element.nextSibling; - } - return element ? element.childNodes : []; - } - - var buildDOM; - if (needsShy) { - buildDOM = function buildDOM(html, contextualElement, dom){ - contextualElement = dom.cloneNode(contextualElement, false); - scriptSafeInnerHTML(contextualElement, html); - return contextualElement.childNodes; - }; - } else { - buildDOM = function buildDOM(html, contextualElement, dom){ - contextualElement = dom.cloneNode(contextualElement, false); - contextualElement.innerHTML = html; - return contextualElement.childNodes; - }; - } - - var buildIESafeDOM; - if (tagNamesRequiringInnerHTMLFix || movesWhitespace) { - buildIESafeDOM = function buildIESafeDOM(html, contextualElement, dom) { - // Make a list of the leading text on script nodes. Include - // script tags without any whitespace for easier processing later. - var spacesBefore = []; - var spacesAfter = []; - if (typeof html === 'string') { - html = html.replace(/(\s*)()(\s*)/g, function(match, tag, spaces) { - spacesAfter.push(spaces); - return tag; - }); - } - - // Fetch nodes - var nodes; - if (tagNamesRequiringInnerHTMLFix[contextualElement.tagName.toLowerCase()]) { - // buildDOMWithFix uses string wrappers for problematic innerHTML. - nodes = buildDOMWithFix(html, contextualElement); - } else { - nodes = buildDOM(html, contextualElement, dom); - } - - // Build a list of script tags, the nodes themselves will be - // mutated as we add test nodes. - var i, j, node, nodeScriptNodes; - var scriptNodes = []; - for (i=0;i 0) { - textNode = dom.document.createTextNode(spaceBefore); - scriptNode.parentNode.insertBefore(textNode, scriptNode); - } - - spaceAfter = spacesAfter[i]; - if (spaceAfter && spaceAfter.length > 0) { - textNode = dom.document.createTextNode(spaceAfter); - scriptNode.parentNode.insertBefore(textNode, scriptNode.nextSibling); - } - } - - return nodes; - }; - } else { - buildIESafeDOM = buildDOM; - } - - // When parsing innerHTML, the browser may set up DOM with some things - // not desired. For example, with a select element context and option - // innerHTML the first option will be marked selected. - // - // This method cleans up some of that, resetting those values back to - // their defaults. - // - function buildSafeDOM(html, contextualElement, dom) { - var childNodes = buildIESafeDOM(html, contextualElement, dom); - - if (contextualElement.tagName === 'SELECT') { - // Walk child nodes - for (var i = 0; childNodes[i]; i++) { - // Find and process the first option child node - if (childNodes[i].tagName === 'OPTION') { - if (detectAutoSelectedOption(childNodes[i].parentNode, childNodes[i], html)) { - // If the first node is selected but does not have an attribute, - // presume it is not really selected. - childNodes[i].parentNode.selectedIndex = -1; - } - break; - } - } - } - - return childNodes; - } - - var buildHTMLDOM; - if (needsIntegrationPointFix) { - buildHTMLDOM = function buildHTMLDOM(html, contextualElement, dom){ - if (svgHTMLIntegrationPoints[contextualElement.tagName]) { - return buildSafeDOM(html, document.createElement('div'), dom); - } else { - return buildSafeDOM(html, contextualElement, dom); - } - }; - } else { - buildHTMLDOM = buildSafeDOM; - } - - __exports__.buildHTMLDOM = buildHTMLDOM; - }); -enifed("morph/dom-helper/classes", - ["exports"], - function(__exports__) { - "use strict"; - var doc = typeof document === 'undefined' ? false : document; - - // PhantomJS has a broken classList. See https://github.com/ariya/phantomjs/issues/12782 - var canClassList = doc && (function(){ - var d = document.createElement('div'); - if (!d.classList) { - return false; - } - d.classList.add('boo'); - d.classList.add('boo', 'baz'); - return (d.className === 'boo baz'); - })(); - - function buildClassList(element) { - var classString = (element.getAttribute('class') || ''); - return classString !== '' && classString !== ' ' ? classString.split(' ') : []; - } - - function intersect(containingArray, valuesArray) { - var containingIndex = 0; - var containingLength = containingArray.length; - var valuesIndex = 0; - var valuesLength = valuesArray.length; - - var intersection = new Array(valuesLength); - - // TODO: rewrite this loop in an optimal manner - for (;containingIndex 0 ? existingClasses.join(' ') : ''); - } - } - - function removeClassesViaAttribute(element, classNames) { - var existingClasses = buildClassList(element); - - var indexes = intersect(classNames, existingClasses); - var didChange = false; - var newClasses = []; - - for (var i=0, l=existingClasses.length; i 0 ? newClasses.join(' ') : ''); - } - } - - var addClasses, removeClasses; - if (canClassList) { - addClasses = function addClasses(element, classNames) { - if (element.classList) { - if (classNames.length === 1) { - element.classList.add(classNames[0]); - } else if (classNames.length === 2) { - element.classList.add(classNames[0], classNames[1]); - } else { - element.classList.add.apply(element.classList, classNames); - } - } else { - addClassesViaAttribute(element, classNames); - } - }; - removeClasses = function removeClasses(element, classNames) { - if (element.classList) { - if (classNames.length === 1) { - element.classList.remove(classNames[0]); - } else if (classNames.length === 2) { - element.classList.remove(classNames[0], classNames[1]); - } else { - element.classList.remove.apply(element.classList, classNames); - } - } else { - removeClassesViaAttribute(element, classNames); - } - }; - } else { - addClasses = addClassesViaAttribute; - removeClasses = removeClassesViaAttribute; - } - - __exports__.addClasses = addClasses; - __exports__.removeClasses = removeClasses; - }); -enifed("morph/dom-helper/prop", - ["exports"], - function(__exports__) { - "use strict"; - function isAttrRemovalValue(value) { - return value === null || value === undefined; - } - - __exports__.isAttrRemovalValue = isAttrRemovalValue;// TODO should this be an o_create kind of thing? - var propertyCaches = {}; - __exports__.propertyCaches = propertyCaches; - function normalizeProperty(element, attrName) { - var tagName = element.tagName; - var key; - var cache = propertyCaches[tagName]; - if (!cache) { - // TODO should this be an o_create kind of thing? - cache = {}; - for (key in element) { - cache[key.toLowerCase()] = key; - } - propertyCaches[tagName] = cache; - } - - // presumes that the attrName has been lowercased. - return cache[attrName]; - } - - __exports__.normalizeProperty = normalizeProperty; - }); -enifed("morph/morph", - ["exports"], - function(__exports__) { - "use strict"; - var splice = Array.prototype.splice; - - function ensureStartEnd(start, end) { - if (start === null || end === null) { - throw new Error('a fragment parent must have boundary nodes in order to detect insertion'); - } - } - - function ensureContext(contextualElement) { - if (!contextualElement || contextualElement.nodeType !== 1) { - throw new Error('An element node must be provided for a contextualElement, you provided ' + - (contextualElement ? 'nodeType ' + contextualElement.nodeType : 'nothing')); - } - } - - // TODO: this is an internal API, this should be an assert - function Morph(parent, start, end, domHelper, contextualElement) { - if (parent.nodeType === 11) { - ensureStartEnd(start, end); - this.element = null; - } else { - this.element = parent; - } - this._parent = parent; - this.start = start; - this.end = end; - this.domHelper = domHelper; - ensureContext(contextualElement); - this.contextualElement = contextualElement; - this.escaped = true; - this.reset(); - } - - Morph.prototype.reset = function() { - this.text = null; - this.owner = null; - this.morphs = null; - this.before = null; - this.after = null; - }; - - Morph.prototype.parent = function () { - if (!this.element) { - var parent = this.start.parentNode; - if (this._parent !== parent) { - this._parent = parent; - } - if (parent.nodeType === 1) { - this.element = parent; - } - } - return this._parent; - }; - - Morph.prototype.destroy = function () { - if (this.owner) { - this.owner.removeMorph(this); - } else { - clear(this.element || this.parent(), this.start, this.end); - } - }; - - Morph.prototype.removeMorph = function (morph) { - var morphs = this.morphs; - for (var i=0, l=morphs.length; i 0 ? morphs[index-1] : null; - var after = index < morphs.length ? morphs[index] : null; - var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); - var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); - var morph = new Morph(parent, start, end, this.domHelper, this.contextualElement); - - morph.owner = this; - morph._update(parent, node); - - if (before !== null) { - morph.before = before; - before.end = start.nextSibling; - before.after = morph; - } - - if (after !== null) { - morph.after = after; - after.before = morph; - after.start = end.previousSibling; - } - - this.morphs.splice(index, 0, morph); - return morph; - }; - - Morph.prototype.replace = function (index, removedLength, addedNodes) { - if (this.morphs === null) { - this.morphs = []; - } - var parent = this.element || this.parent(); - var morphs = this.morphs; - var before = index > 0 ? morphs[index-1] : null; - var after = index+removedLength < morphs.length ? morphs[index+removedLength] : null; - var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); - var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); - var addedLength = addedNodes === undefined ? 0 : addedNodes.length; - var args, i, current; - - if (removedLength > 0) { - clear(parent, start, end); - } - - if (addedLength === 0) { - if (before !== null) { - before.after = after; - before.end = end; - } - if (after !== null) { - after.before = before; - after.start = start; - } - morphs.splice(index, removedLength); - return; - } - - args = new Array(addedLength+2); - if (addedLength > 0) { - for (i=0; i " + n.nextStates.map(function(s) { return s.debug() }).join(" or ") + " )"; - }).join(", ") - } - END IF **/ - - // This is a somewhat naive strategy, but should work in a lot of cases - // A better strategy would properly resolve /posts/:id/new and /posts/edit/:id. - // - // This strategy generally prefers more static and less dynamic matching. - // Specifically, it - // - // * prefers fewer stars to more, then - // * prefers using stars for less of the match to more, then - // * prefers fewer dynamic segments to more, then - // * prefers more static segments to more - function sortSolutions(states) { - return states.sort(function(a, b) { - if (a.types.stars !== b.types.stars) { return a.types.stars - b.types.stars; } - - if (a.types.stars) { - if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } - if (a.types.dynamics !== b.types.dynamics) { return b.types.dynamics - a.types.dynamics; } - } - - if (a.types.dynamics !== b.types.dynamics) { return a.types.dynamics - b.types.dynamics; } - if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } - - return 0; - }); - } - - function recognizeChar(states, ch) { - var nextStates = []; - - for (var i=0, l=states.length; i 2 && key.slice(keyLength -2) === '[]') { - isArray = true; - key = key.slice(0, keyLength - 2); - if(!queryParams[key]) { - queryParams[key] = []; - } - } - value = pair[1] ? decodeQueryParamPart(pair[1]) : ''; - } - if (isArray) { - queryParams[key].push(value); - } else { - queryParams[key] = value; - } - } - return queryParams; - }, - - recognize: function(path) { - var states = [ this.rootState ], - pathLen, i, l, queryStart, queryParams = {}, - isSlashDropped = false; - - queryStart = path.indexOf('?'); - if (queryStart !== -1) { - var queryString = path.substr(queryStart + 1, path.length); - path = path.substr(0, queryStart); - queryParams = this.parseQueryString(queryString); - } - - path = decodeURI(path); - - // DEBUG GROUP path - - if (path.charAt(0) !== "/") { path = "/" + path; } - - pathLen = path.length; - if (pathLen > 1 && path.charAt(pathLen - 1) === "/") { - path = path.substr(0, pathLen - 1); - isSlashDropped = true; - } - - for (i=0, l=path.length; i= 0 && proceed; --i) { - var route = routes[i]; - recognizer.add(routes, { as: route.handler }); - proceed = route.path === '/' || route.path === '' || route.handler.slice(-6) === '.index'; - } - }); - }, - - hasRoute: function(route) { - return this.recognizer.hasRoute(route); - }, - - queryParamsTransition: function(changelist, wasTransitioning, oldState, newState) { - var router = this; - - fireQueryParamDidChange(this, newState, changelist); - - if (!wasTransitioning && this.activeTransition) { - // One of the handlers in queryParamsDidChange - // caused a transition. Just return that transition. - return this.activeTransition; - } else { - // Running queryParamsDidChange didn't change anything. - // Just update query params and be on our way. - - // We have to return a noop transition that will - // perform a URL update at the end. This gives - // the user the ability to set the url update - // method (default is replaceState). - var newTransition = new Transition(this); - newTransition.queryParamsOnly = true; - - oldState.queryParams = finalizeQueryParamChange(this, newState.handlerInfos, newState.queryParams, newTransition); - - newTransition.promise = newTransition.promise.then(function(result) { - updateURL(newTransition, oldState, true); - if (router.didTransition) { - router.didTransition(router.currentHandlerInfos); - } - return result; - }, null, promiseLabel("Transition complete")); - return newTransition; - } - }, - - // NOTE: this doesn't really belong here, but here - // it shall remain until our ES6 transpiler can - // handle cyclical deps. - transitionByIntent: function(intent, isIntermediate) { - try { - return getTransitionByIntent.apply(this, arguments); - } catch(e) { - return new Transition(this, intent, null, e); - } - }, - - /** - Clears the current and target route handlers and triggers exit - on each of them starting at the leaf and traversing up through - its ancestors. - */ - reset: function() { - if (this.state) { - forEach(this.state.handlerInfos.slice().reverse(), function(handlerInfo) { - var handler = handlerInfo.handler; - callHook(handler, 'exit'); - }); - } - - this.state = new TransitionState(); - this.currentHandlerInfos = null; - }, - - activeTransition: null, - - /** - var handler = handlerInfo.handler; - The entry point for handling a change to the URL (usually - via the back and forward button). - - Returns an Array of handlers and the parameters associated - with those parameters. - - @param {String} url a URL to process - - @return {Array} an Array of `[handler, parameter]` tuples - */ - handleURL: function(url) { - // Perform a URL-based transition, but don't change - // the URL afterward, since it already happened. - var args = slice.call(arguments); - if (url.charAt(0) !== '/') { args[0] = '/' + url; } - - return doTransition(this, args).method(null); - }, - - /** - Hook point for updating the URL. - - @param {String} url a URL to update to - */ - updateURL: function() { - throw new Error("updateURL is not implemented"); - }, - - /** - Hook point for replacing the current URL, i.e. with replaceState - - By default this behaves the same as `updateURL` - - @param {String} url a URL to update to - */ - replaceURL: function(url) { - this.updateURL(url); - }, - - /** - Transition into the specified named route. - - If necessary, trigger the exit callback on any handlers - that are no longer represented by the target route. - - @param {String} name the name of the route - */ - transitionTo: function(name) { - return doTransition(this, arguments); - }, - - intermediateTransitionTo: function(name) { - return doTransition(this, arguments, true); - }, - - refresh: function(pivotHandler) { - var state = this.activeTransition ? this.activeTransition.state : this.state; - var handlerInfos = state.handlerInfos; - var params = {}; - for (var i = 0, len = handlerInfos.length; i < len; ++i) { - var handlerInfo = handlerInfos[i]; - params[handlerInfo.name] = handlerInfo.params || {}; - } - - log(this, "Starting a refresh transition"); - var intent = new NamedTransitionIntent({ - name: handlerInfos[handlerInfos.length - 1].name, - pivotHandler: pivotHandler || handlerInfos[0].handler, - contexts: [], // TODO collect contexts...? - queryParams: this._changedQueryParams || state.queryParams || {} - }); - - return this.transitionByIntent(intent, false); - }, - - /** - Identical to `transitionTo` except that the current URL will be replaced - if possible. - - This method is intended primarily for use with `replaceState`. - - @param {String} name the name of the route - */ - replaceWith: function(name) { - return doTransition(this, arguments).method('replace'); - }, - - /** - Take a named route and context objects and generate a - URL. - - @param {String} name the name of the route to generate - a URL for - @param {...Object} objects a list of objects to serialize - - @return {String} a URL - */ - generate: function(handlerName) { - - var partitionedArgs = extractQueryParams(slice.call(arguments, 1)), - suppliedParams = partitionedArgs[0], - queryParams = partitionedArgs[1]; - - // Construct a TransitionIntent with the provided params - // and apply it to the present state of the router. - var intent = new NamedTransitionIntent({ name: handlerName, contexts: suppliedParams }); - var state = intent.applyToState(this.state, this.recognizer, this.getHandler); - var params = {}; - - for (var i = 0, len = state.handlerInfos.length; i < len; ++i) { - var handlerInfo = state.handlerInfos[i]; - var handlerParams = handlerInfo.serialize(); - merge(params, handlerParams); - } - params.queryParams = queryParams; - - return this.recognizer.generate(handlerName, params); - }, - - applyIntent: function(handlerName, contexts) { - var intent = new NamedTransitionIntent({ - name: handlerName, - contexts: contexts - }); - - var state = this.activeTransition && this.activeTransition.state || this.state; - return intent.applyToState(state, this.recognizer, this.getHandler); - }, - - isActiveIntent: function(handlerName, contexts, queryParams) { - var targetHandlerInfos = this.state.handlerInfos, - found = false, names, object, handlerInfo, handlerObj, i, len; - - if (!targetHandlerInfos.length) { return false; } - - var targetHandler = targetHandlerInfos[targetHandlerInfos.length - 1].name; - var recogHandlers = this.recognizer.handlersFor(targetHandler); - - var index = 0; - for (len = recogHandlers.length; index < len; ++index) { - handlerInfo = targetHandlerInfos[index]; - if (handlerInfo.name === handlerName) { break; } - } - - if (index === recogHandlers.length) { - // The provided route name isn't even in the route hierarchy. - return false; - } - - var state = new TransitionState(); - state.handlerInfos = targetHandlerInfos.slice(0, index + 1); - recogHandlers = recogHandlers.slice(0, index + 1); - - var intent = new NamedTransitionIntent({ - name: targetHandler, - contexts: contexts - }); - - var newState = intent.applyToHandlers(state, recogHandlers, this.getHandler, targetHandler, true, true); - - var handlersEqual = handlerInfosEqual(newState.handlerInfos, state.handlerInfos); - if (!queryParams || !handlersEqual) { - return handlersEqual; - } - - // Get a hash of QPs that will still be active on new route - var activeQPsOnNewHandler = {}; - merge(activeQPsOnNewHandler, queryParams); - - var activeQueryParams = this.state.queryParams; - for (var key in activeQueryParams) { - if (activeQueryParams.hasOwnProperty(key) && - activeQPsOnNewHandler.hasOwnProperty(key)) { - activeQPsOnNewHandler[key] = activeQueryParams[key]; - } - } - - return handlersEqual && !getChangelist(activeQPsOnNewHandler, queryParams); - }, - - isActive: function(handlerName) { - var partitionedArgs = extractQueryParams(slice.call(arguments, 1)); - return this.isActiveIntent(handlerName, partitionedArgs[0], partitionedArgs[1]); - }, - - trigger: function(name) { - var args = slice.call(arguments); - trigger(this, this.currentHandlerInfos, false, args); - }, - - /** - Hook point for logging transition status updates. - - @param {String} message The message to log. - */ - log: null, - - _willChangeContextEvent: 'willChangeContext', - _triggerWillChangeContext: function(handlerInfos, newTransition) { - trigger(this, handlerInfos, true, [this._willChangeContextEvent, newTransition]); - }, - - _triggerWillLeave: function(handlerInfos, newTransition, leavingChecker) { - trigger(this, handlerInfos, true, ['willLeave', newTransition, leavingChecker]); - } - }; - - /** - @private - - Fires queryParamsDidChange event - */ - function fireQueryParamDidChange(router, newState, queryParamChangelist) { - // If queryParams changed trigger event - if (queryParamChangelist) { - - // This is a little hacky but we need some way of storing - // changed query params given that no activeTransition - // is guaranteed to have occurred. - router._changedQueryParams = queryParamChangelist.all; - trigger(router, newState.handlerInfos, true, ['queryParamsDidChange', queryParamChangelist.changed, queryParamChangelist.all, queryParamChangelist.removed]); - router._changedQueryParams = null; - } - } - - /** - @private - - Takes an Array of `HandlerInfo`s, figures out which ones are - exiting, entering, or changing contexts, and calls the - proper handler hooks. - - For example, consider the following tree of handlers. Each handler is - followed by the URL segment it handles. - - ``` - |~index ("/") - | |~posts ("/posts") - | | |-showPost ("/:id") - | | |-newPost ("/new") - | | |-editPost ("/edit") - | |~about ("/about/:id") - ``` - - Consider the following transitions: - - 1. A URL transition to `/posts/1`. - 1. Triggers the `*model` callbacks on the - `index`, `posts`, and `showPost` handlers - 2. Triggers the `enter` callback on the same - 3. Triggers the `setup` callback on the same - 2. A direct transition to `newPost` - 1. Triggers the `exit` callback on `showPost` - 2. Triggers the `enter` callback on `newPost` - 3. Triggers the `setup` callback on `newPost` - 3. A direct transition to `about` with a specified - context object - 1. Triggers the `exit` callback on `newPost` - and `posts` - 2. Triggers the `serialize` callback on `about` - 3. Triggers the `enter` callback on `about` - 4. Triggers the `setup` callback on `about` - - @param {Router} transition - @param {TransitionState} newState - */ - function setupContexts(router, newState, transition) { - var partition = partitionHandlers(router.state, newState); - - forEach(partition.exited, function(handlerInfo) { - var handler = handlerInfo.handler; - delete handler.context; - - callHook(handler, 'reset', true, transition); - callHook(handler, 'exit', transition); - }); - - var oldState = router.oldState = router.state; - router.state = newState; - var currentHandlerInfos = router.currentHandlerInfos = partition.unchanged.slice(); - - try { - forEach(partition.reset, function(handlerInfo) { - var handler = handlerInfo.handler; - callHook(handler, 'reset', false, transition); - }); - - forEach(partition.updatedContext, function(handlerInfo) { - return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, false, transition); - }); - - forEach(partition.entered, function(handlerInfo) { - return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, true, transition); - }); - } catch(e) { - router.state = oldState; - router.currentHandlerInfos = oldState.handlerInfos; - throw e; - } - - router.state.queryParams = finalizeQueryParamChange(router, currentHandlerInfos, newState.queryParams, transition); - } - - - /** - @private - - Helper method used by setupContexts. Handles errors or redirects - that may happen in enter/setup. - */ - function handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, enter, transition) { - - var handler = handlerInfo.handler, - context = handlerInfo.context; - - if (enter) { - callHook(handler, 'enter', transition); - } - if (transition && transition.isAborted) { - throw new TransitionAborted(); - } - - handler.context = context; - callHook(handler, 'contextDidChange'); - - callHook(handler, 'setup', context, transition); - if (transition && transition.isAborted) { - throw new TransitionAborted(); - } - - currentHandlerInfos.push(handlerInfo); - - return true; - } - - - /** - @private - - This function is called when transitioning from one URL to - another to determine which handlers are no longer active, - which handlers are newly active, and which handlers remain - active but have their context changed. - - Take a list of old handlers and new handlers and partition - them into four buckets: - - * unchanged: the handler was active in both the old and - new URL, and its context remains the same - * updated context: the handler was active in both the - old and new URL, but its context changed. The handler's - `setup` method, if any, will be called with the new - context. - * exited: the handler was active in the old URL, but is - no longer active. - * entered: the handler was not active in the old URL, but - is now active. - - The PartitionedHandlers structure has four fields: - - * `updatedContext`: a list of `HandlerInfo` objects that - represent handlers that remain active but have a changed - context - * `entered`: a list of `HandlerInfo` objects that represent - handlers that are newly active - * `exited`: a list of `HandlerInfo` objects that are no - longer active. - * `unchanged`: a list of `HanderInfo` objects that remain active. - - @param {Array[HandlerInfo]} oldHandlers a list of the handler - information for the previous URL (or `[]` if this is the - first handled transition) - @param {Array[HandlerInfo]} newHandlers a list of the handler - information for the new URL - - @return {Partition} - */ - function partitionHandlers(oldState, newState) { - var oldHandlers = oldState.handlerInfos; - var newHandlers = newState.handlerInfos; - - var handlers = { - updatedContext: [], - exited: [], - entered: [], - unchanged: [] - }; - - var handlerChanged, contextChanged = false, i, l; - - for (i=0, l=newHandlers.length; i= 0; --i) { - var handlerInfo = handlerInfos[i]; - merge(params, handlerInfo.params); - if (handlerInfo.handler.inaccessibleByURL) { - urlMethod = null; - } - } - - if (urlMethod) { - params.queryParams = transition._visibleQueryParams || state.queryParams; - var url = router.recognizer.generate(handlerName, params); - - if (urlMethod === 'replace') { - router.replaceURL(url); - } else { - router.updateURL(url); - } - } - } - - /** - @private - - Updates the URL (if necessary) and calls `setupContexts` - to update the router's array of `currentHandlerInfos`. - */ - function finalizeTransition(transition, newState) { - - try { - log(transition.router, transition.sequence, "Resolved all models on destination route; finalizing transition."); - - var router = transition.router, - handlerInfos = newState.handlerInfos, - seq = transition.sequence; - - // Run all the necessary enter/setup/exit hooks - setupContexts(router, newState, transition); - - // Check if a redirect occurred in enter/setup - if (transition.isAborted) { - // TODO: cleaner way? distinguish b/w targetHandlerInfos? - router.state.handlerInfos = router.currentHandlerInfos; - return Promise.reject(logAbort(transition)); - } - - updateURL(transition, newState, transition.intent.url); - - transition.isActive = false; - router.activeTransition = null; - - trigger(router, router.currentHandlerInfos, true, ['didTransition']); - - if (router.didTransition) { - router.didTransition(router.currentHandlerInfos); - } - - log(router, transition.sequence, "TRANSITION COMPLETE."); - - // Resolve with the final handler. - return handlerInfos[handlerInfos.length - 1].handler; - } catch(e) { - if (!((e instanceof TransitionAborted))) { - //var erroneousHandler = handlerInfos.pop(); - var infos = transition.state.handlerInfos; - transition.trigger(true, 'error', e, transition, infos[infos.length-1].handler); - transition.abort(); - } - - throw e; - } - } - - /** - @private - - Begins and returns a Transition based on the provided - arguments. Accepts arguments in the form of both URL - transitions and named transitions. - - @param {Router} router - @param {Array[Object]} args arguments passed to transitionTo, - replaceWith, or handleURL - */ - function doTransition(router, args, isIntermediate) { - // Normalize blank transitions to root URL transitions. - var name = args[0] || '/'; - - var lastArg = args[args.length-1]; - var queryParams = {}; - if (lastArg && lastArg.hasOwnProperty('queryParams')) { - queryParams = pop.call(args).queryParams; - } - - var intent; - if (args.length === 0) { - - log(router, "Updating query params"); - - // A query param update is really just a transition - // into the route you're already on. - var handlerInfos = router.state.handlerInfos; - intent = new NamedTransitionIntent({ - name: handlerInfos[handlerInfos.length - 1].name, - contexts: [], - queryParams: queryParams - }); - - } else if (name.charAt(0) === '/') { - - log(router, "Attempting URL transition to " + name); - intent = new URLTransitionIntent({ url: name }); - - } else { - - log(router, "Attempting transition to " + name); - intent = new NamedTransitionIntent({ - name: args[0], - contexts: slice.call(args, 1), - queryParams: queryParams - }); - } - - return router.transitionByIntent(intent, isIntermediate); - } - - function handlerInfosEqual(handlerInfos, otherHandlerInfos) { - if (handlerInfos.length !== otherHandlerInfos.length) { - return false; - } - - for (var i = 0, len = handlerInfos.length; i < len; ++i) { - if (handlerInfos[i] !== otherHandlerInfos[i]) { - return false; - } - } - return true; - } - - function finalizeQueryParamChange(router, resolvedHandlers, newQueryParams, transition) { - // We fire a finalizeQueryParamChange event which - // gives the new route hierarchy a chance to tell - // us which query params it's consuming and what - // their final values are. If a query param is - // no longer consumed in the final route hierarchy, - // its serialized segment will be removed - // from the URL. - - for (var k in newQueryParams) { - if (newQueryParams.hasOwnProperty(k) && - newQueryParams[k] === null) { - delete newQueryParams[k]; - } - } - - var finalQueryParamsArray = []; - trigger(router, resolvedHandlers, true, ['finalizeQueryParamChange', newQueryParams, finalQueryParamsArray, transition]); - - if (transition) { - transition._visibleQueryParams = {}; - } - - var finalQueryParams = {}; - for (var i = 0, len = finalQueryParamsArray.length; i < len; ++i) { - var qp = finalQueryParamsArray[i]; - finalQueryParams[qp.key] = qp.value; - if (transition && qp.visible !== false) { - transition._visibleQueryParams[qp.key] = qp.value; - } - } - return finalQueryParams; - } - - function notifyExistingHandlers(router, newState, newTransition) { - var oldHandlers = router.state.handlerInfos, - changing = [], - leavingIndex = null, - leaving, leavingChecker, i, oldHandlerLen, oldHandler, newHandler; - - oldHandlerLen = oldHandlers.length; - for (i = 0; i < oldHandlerLen; i++) { - oldHandler = oldHandlers[i]; - newHandler = newState.handlerInfos[i]; - - if (!newHandler || oldHandler.name !== newHandler.name) { - leavingIndex = i; - break; - } - - if (!newHandler.isResolved) { - changing.push(oldHandler); - } - } - - if (leavingIndex !== null) { - leaving = oldHandlers.slice(leavingIndex, oldHandlerLen); - leavingChecker = function(name) { - for (var h = 0, len = leaving.length; h < len; h++) { - if (leaving[h].name === name) { - return true; - } - } - return false; - }; - - router._triggerWillLeave(leaving, newTransition, leavingChecker); - } - - if (changing.length > 0) { - router._triggerWillChangeContext(changing, newTransition); - } - - trigger(router, oldHandlers, true, ['willTransition', newTransition]); - } - - __exports__["default"] = Router; - }); -enifed("router/transition-intent", - ["./utils","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var merge = __dependency1__.merge; - - function TransitionIntent(props) { - this.initialize(props); - - // TODO: wat - this.data = this.data || {}; - } - - TransitionIntent.prototype = { - initialize: null, - applyToState: null - }; - - __exports__["default"] = TransitionIntent; - }); -enifed("router/transition-intent/named-transition-intent", - ["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var TransitionIntent = __dependency1__["default"]; - var TransitionState = __dependency2__["default"]; - var handlerInfoFactory = __dependency3__["default"]; - var isParam = __dependency4__.isParam; - var extractQueryParams = __dependency4__.extractQueryParams; - var merge = __dependency4__.merge; - var subclass = __dependency4__.subclass; - - __exports__["default"] = subclass(TransitionIntent, { - name: null, - pivotHandler: null, - contexts: null, - queryParams: null, - - initialize: function(props) { - this.name = props.name; - this.pivotHandler = props.pivotHandler; - this.contexts = props.contexts || []; - this.queryParams = props.queryParams; - }, - - applyToState: function(oldState, recognizer, getHandler, isIntermediate) { - - var partitionedArgs = extractQueryParams([this.name].concat(this.contexts)), - pureArgs = partitionedArgs[0], - queryParams = partitionedArgs[1], - handlers = recognizer.handlersFor(pureArgs[0]); - - var targetRouteName = handlers[handlers.length-1].handler; - - return this.applyToHandlers(oldState, handlers, getHandler, targetRouteName, isIntermediate); - }, - - applyToHandlers: function(oldState, handlers, getHandler, targetRouteName, isIntermediate, checkingIfActive) { - - var i, len; - var newState = new TransitionState(); - var objects = this.contexts.slice(0); - - var invalidateIndex = handlers.length; - - // Pivot handlers are provided for refresh transitions - if (this.pivotHandler) { - for (i = 0, len = handlers.length; i < len; ++i) { - if (getHandler(handlers[i].handler) === this.pivotHandler) { - invalidateIndex = i; - break; - } - } - } - - var pivotHandlerFound = !this.pivotHandler; - - for (i = handlers.length - 1; i >= 0; --i) { - var result = handlers[i]; - var name = result.handler; - var handler = getHandler(name); - - var oldHandlerInfo = oldState.handlerInfos[i]; - var newHandlerInfo = null; - - if (result.names.length > 0) { - if (i >= invalidateIndex) { - newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); - } else { - newHandlerInfo = this.getHandlerInfoForDynamicSegment(name, handler, result.names, objects, oldHandlerInfo, targetRouteName, i); - } - } else { - // This route has no dynamic segment. - // Therefore treat as a param-based handlerInfo - // with empty params. This will cause the `model` - // hook to be called with empty params, which is desirable. - newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); - } - - if (checkingIfActive) { - // If we're performing an isActive check, we want to - // serialize URL params with the provided context, but - // ignore mismatches between old and new context. - newHandlerInfo = newHandlerInfo.becomeResolved(null, newHandlerInfo.context); - var oldContext = oldHandlerInfo && oldHandlerInfo.context; - if (result.names.length > 0 && newHandlerInfo.context === oldContext) { - // If contexts match in isActive test, assume params also match. - // This allows for flexibility in not requiring that every last - // handler provide a `serialize` method - newHandlerInfo.params = oldHandlerInfo && oldHandlerInfo.params; - } - newHandlerInfo.context = oldContext; - } - - var handlerToUse = oldHandlerInfo; - if (i >= invalidateIndex || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { - invalidateIndex = Math.min(i, invalidateIndex); - handlerToUse = newHandlerInfo; - } - - if (isIntermediate && !checkingIfActive) { - handlerToUse = handlerToUse.becomeResolved(null, handlerToUse.context); - } - - newState.handlerInfos.unshift(handlerToUse); - } - - if (objects.length > 0) { - throw new Error("More context objects were passed than there are dynamic segments for the route: " + targetRouteName); - } - - if (!isIntermediate) { - this.invalidateChildren(newState.handlerInfos, invalidateIndex); - } - - merge(newState.queryParams, this.queryParams || {}); - - return newState; - }, - - invalidateChildren: function(handlerInfos, invalidateIndex) { - for (var i = invalidateIndex, l = handlerInfos.length; i < l; ++i) { - var handlerInfo = handlerInfos[i]; - handlerInfos[i] = handlerInfos[i].getUnresolved(); - } - }, - - getHandlerInfoForDynamicSegment: function(name, handler, names, objects, oldHandlerInfo, targetRouteName, i) { - - var numNames = names.length; - var objectToUse; - if (objects.length > 0) { - - // Use the objects provided for this transition. - objectToUse = objects[objects.length - 1]; - if (isParam(objectToUse)) { - return this.createParamHandlerInfo(name, handler, names, objects, oldHandlerInfo); - } else { - objects.pop(); - } - } else if (oldHandlerInfo && oldHandlerInfo.name === name) { - // Reuse the matching oldHandlerInfo - return oldHandlerInfo; - } else { - if (this.preTransitionState) { - var preTransitionHandlerInfo = this.preTransitionState.handlerInfos[i]; - objectToUse = preTransitionHandlerInfo && preTransitionHandlerInfo.context; - } else { - // Ideally we should throw this error to provide maximal - // information to the user that not enough context objects - // were provided, but this proves too cumbersome in Ember - // in cases where inner template helpers are evaluated - // before parent helpers un-render, in which cases this - // error somewhat prematurely fires. - //throw new Error("Not enough context objects were provided to complete a transition to " + targetRouteName + ". Specifically, the " + name + " route needs an object that can be serialized into its dynamic URL segments [" + names.join(', ') + "]"); - return oldHandlerInfo; - } - } - - return handlerInfoFactory('object', { - name: name, - handler: handler, - context: objectToUse, - names: names - }); - }, - - createParamHandlerInfo: function(name, handler, names, objects, oldHandlerInfo) { - var params = {}; - - // Soak up all the provided string/numbers - var numNames = names.length; - while (numNames--) { - - // Only use old params if the names match with the new handler - var oldParams = (oldHandlerInfo && name === oldHandlerInfo.name && oldHandlerInfo.params) || {}; - - var peek = objects[objects.length - 1]; - var paramName = names[numNames]; - if (isParam(peek)) { - params[paramName] = "" + objects.pop(); - } else { - // If we're here, this means only some of the params - // were string/number params, so try and use a param - // value from a previous handler. - if (oldParams.hasOwnProperty(paramName)) { - params[paramName] = oldParams[paramName]; - } else { - throw new Error("You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route " + name); - } - } - } - - return handlerInfoFactory('param', { - name: name, - handler: handler, - params: params - }); - } - }); - }); -enifed("router/transition-intent/url-transition-intent", - ["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var TransitionIntent = __dependency1__["default"]; - var TransitionState = __dependency2__["default"]; - var handlerInfoFactory = __dependency3__["default"]; - var oCreate = __dependency4__.oCreate; - var merge = __dependency4__.merge; - var subclass = __dependency4__.subclass; - - __exports__["default"] = subclass(TransitionIntent, { - url: null, - - initialize: function(props) { - this.url = props.url; - }, - - applyToState: function(oldState, recognizer, getHandler) { - var newState = new TransitionState(); - - var results = recognizer.recognize(this.url), - queryParams = {}, - i, len; - - if (!results) { - throw new UnrecognizedURLError(this.url); - } - - var statesDiffer = false; - - for (i = 0, len = results.length; i < len; ++i) { - var result = results[i]; - var name = result.handler; - var handler = getHandler(name); - - if (handler.inaccessibleByURL) { - throw new UnrecognizedURLError(this.url); - } - - var newHandlerInfo = handlerInfoFactory('param', { - name: name, - handler: handler, - params: result.params - }); - - var oldHandlerInfo = oldState.handlerInfos[i]; - if (statesDiffer || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { - statesDiffer = true; - newState.handlerInfos[i] = newHandlerInfo; - } else { - newState.handlerInfos[i] = oldHandlerInfo; - } - } - - merge(newState.queryParams, results.queryParams); - - return newState; - } - }); - - /** - Promise reject reasons passed to promise rejection - handlers for failed transitions. - */ - function UnrecognizedURLError(message) { - this.message = (message || "UnrecognizedURLError"); - this.name = "UnrecognizedURLError"; - } - }); -enifed("router/transition-state", - ["./handler-info","./utils","rsvp/promise","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var ResolvedHandlerInfo = __dependency1__.ResolvedHandlerInfo; - var forEach = __dependency2__.forEach; - var promiseLabel = __dependency2__.promiseLabel; - var callHook = __dependency2__.callHook; - var Promise = __dependency3__["default"]; - - function TransitionState(other) { - this.handlerInfos = []; - this.queryParams = {}; - this.params = {}; - } - - TransitionState.prototype = { - handlerInfos: null, - queryParams: null, - params: null, - - promiseLabel: function(label) { - var targetName = ''; - forEach(this.handlerInfos, function(handlerInfo) { - if (targetName !== '') { - targetName += '.'; - } - targetName += handlerInfo.name; - }); - return promiseLabel("'" + targetName + "': " + label); - }, - - resolve: function(shouldContinue, payload) { - var self = this; - // First, calculate params for this state. This is useful - // information to provide to the various route hooks. - var params = this.params; - forEach(this.handlerInfos, function(handlerInfo) { - params[handlerInfo.name] = handlerInfo.params || {}; - }); - - payload = payload || {}; - payload.resolveIndex = 0; - - var currentState = this; - var wasAborted = false; - - // The prelude RSVP.resolve() asyncs us into the promise land. - return Promise.resolve(null, this.promiseLabel("Start transition")) - .then(resolveOneHandlerInfo, null, this.promiseLabel('Resolve handler'))['catch'](handleError, this.promiseLabel('Handle error')); - - function innerShouldContinue() { - return Promise.resolve(shouldContinue(), currentState.promiseLabel("Check if should continue"))['catch'](function(reason) { - // We distinguish between errors that occurred - // during resolution (e.g. beforeModel/model/afterModel), - // and aborts due to a rejecting promise from shouldContinue(). - wasAborted = true; - return Promise.reject(reason); - }, currentState.promiseLabel("Handle abort")); - } - - function handleError(error) { - // This is the only possible - // reject value of TransitionState#resolve - var handlerInfos = currentState.handlerInfos; - var errorHandlerIndex = payload.resolveIndex >= handlerInfos.length ? - handlerInfos.length - 1 : payload.resolveIndex; - return Promise.reject({ - error: error, - handlerWithError: currentState.handlerInfos[errorHandlerIndex].handler, - wasAborted: wasAborted, - state: currentState - }); - } - - function proceed(resolvedHandlerInfo) { - var wasAlreadyResolved = currentState.handlerInfos[payload.resolveIndex].isResolved; - - // Swap the previously unresolved handlerInfo with - // the resolved handlerInfo - currentState.handlerInfos[payload.resolveIndex++] = resolvedHandlerInfo; - - if (!wasAlreadyResolved) { - // Call the redirect hook. The reason we call it here - // vs. afterModel is so that redirects into child - // routes don't re-run the model hooks for this - // already-resolved route. - var handler = resolvedHandlerInfo.handler; - callHook(handler, 'redirect', resolvedHandlerInfo.context, payload); - } - - // Proceed after ensuring that the redirect hook - // didn't abort this transition by transitioning elsewhere. - return innerShouldContinue().then(resolveOneHandlerInfo, null, currentState.promiseLabel('Resolve handler')); - } - - function resolveOneHandlerInfo() { - if (payload.resolveIndex === currentState.handlerInfos.length) { - // This is is the only possible - // fulfill value of TransitionState#resolve - return { - error: null, - state: currentState - }; - } - - var handlerInfo = currentState.handlerInfos[payload.resolveIndex]; - - return handlerInfo.resolve(innerShouldContinue, payload) - .then(proceed, null, currentState.promiseLabel('Proceed')); - } - } - }; - - __exports__["default"] = TransitionState; - }); -enifed("router/transition", - ["rsvp/promise","./handler-info","./utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - var ResolvedHandlerInfo = __dependency2__.ResolvedHandlerInfo; - var trigger = __dependency3__.trigger; - var slice = __dependency3__.slice; - var log = __dependency3__.log; - var promiseLabel = __dependency3__.promiseLabel; - - /** - @private - - A Transition is a thennable (a promise-like object) that represents - an attempt to transition to another route. It can be aborted, either - explicitly via `abort` or by attempting another transition while a - previous one is still underway. An aborted transition can also - be `retry()`d later. - */ - function Transition(router, intent, state, error) { - var transition = this; - this.state = state || router.state; - this.intent = intent; - this.router = router; - this.data = this.intent && this.intent.data || {}; - this.resolvedModels = {}; - this.queryParams = {}; - - if (error) { - this.promise = Promise.reject(error); - this.error = error; - return; - } - - if (state) { - this.params = state.params; - this.queryParams = state.queryParams; - this.handlerInfos = state.handlerInfos; - - var len = state.handlerInfos.length; - if (len) { - this.targetName = state.handlerInfos[len-1].name; - } - - for (var i = 0; i < len; ++i) { - var handlerInfo = state.handlerInfos[i]; - - // TODO: this all seems hacky - if (!handlerInfo.isResolved) { break; } - this.pivotHandler = handlerInfo.handler; - } - - this.sequence = Transition.currentSequence++; - this.promise = state.resolve(checkForAbort, this)['catch'](function(result) { - if (result.wasAborted || transition.isAborted) { - return Promise.reject(logAbort(transition)); - } else { - transition.trigger('error', result.error, transition, result.handlerWithError); - transition.abort(); - return Promise.reject(result.error); - } - }, promiseLabel('Handle Abort')); - } else { - this.promise = Promise.resolve(this.state); - this.params = {}; - } - - function checkForAbort() { - if (transition.isAborted) { - return Promise.reject(undefined, promiseLabel("Transition aborted - reject")); - } - } - } - - Transition.currentSequence = 0; - - Transition.prototype = { - targetName: null, - urlMethod: 'update', - intent: null, - params: null, - pivotHandler: null, - resolveIndex: 0, - handlerInfos: null, - resolvedModels: null, - isActive: true, - state: null, - queryParamsOnly: false, - - isTransition: true, - - isExiting: function(handler) { - var handlerInfos = this.handlerInfos; - for (var i = 0, len = handlerInfos.length; i < len; ++i) { - var handlerInfo = handlerInfos[i]; - if (handlerInfo.name === handler || handlerInfo.handler === handler) { - return false; - } - } - return true; - }, - - /** - @public - - The Transition's internal promise. Calling `.then` on this property - is that same as calling `.then` on the Transition object itself, but - this property is exposed for when you want to pass around a - Transition's promise, but not the Transition object itself, since - Transition object can be externally `abort`ed, while the promise - cannot. - */ - promise: null, - - /** - @public - - Custom state can be stored on a Transition's `data` object. - This can be useful for decorating a Transition within an earlier - hook and shared with a later hook. Properties set on `data` will - be copied to new transitions generated by calling `retry` on this - transition. - */ - data: null, - - /** - @public - - A standard promise hook that resolves if the transition - succeeds and rejects if it fails/redirects/aborts. - - Forwards to the internal `promise` property which you can - use in situations where you want to pass around a thennable, - but not the Transition itself. - - @param {Function} onFulfilled - @param {Function} onRejected - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} - */ - then: function(onFulfilled, onRejected, label) { - return this.promise.then(onFulfilled, onRejected, label); - }, - - /** - @public - - Forwards to the internal `promise` property which you can - use in situations where you want to pass around a thennable, - but not the Transition itself. - - @method catch - @param {Function} onRejection - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} - */ - "catch": function(onRejection, label) { - return this.promise["catch"](onRejection, label); - }, - - /** - @public - - Forwards to the internal `promise` property which you can - use in situations where you want to pass around a thennable, - but not the Transition itself. - - @method finally - @param {Function} callback - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} - */ - "finally": function(callback, label) { - return this.promise["finally"](callback, label); - }, - - /** - @public - - Aborts the Transition. Note you can also implicitly abort a transition - by initiating another transition while a previous one is underway. - */ - abort: function() { - if (this.isAborted) { return this; } - log(this.router, this.sequence, this.targetName + ": transition was aborted"); - this.intent.preTransitionState = this.router.state; - this.isAborted = true; - this.isActive = false; - this.router.activeTransition = null; - return this; - }, - - /** - @public - - Retries a previously-aborted transition (making sure to abort the - transition if it's still active). Returns a new transition that - represents the new attempt to transition. - */ - retry: function() { - // TODO: add tests for merged state retry()s - this.abort(); - return this.router.transitionByIntent(this.intent, false); - }, - - /** - @public - - Sets the URL-changing method to be employed at the end of a - successful transition. By default, a new Transition will just - use `updateURL`, but passing 'replace' to this method will - cause the URL to update using 'replaceWith' instead. Omitting - a parameter will disable the URL change, allowing for transitions - that don't update the URL at completion (this is also used for - handleURL, since the URL has already changed before the - transition took place). - - @param {String} method the type of URL-changing method to use - at the end of a transition. Accepted values are 'replace', - falsy values, or any other non-falsy value (which is - interpreted as an updateURL transition). - - @return {Transition} this transition - */ - method: function(method) { - this.urlMethod = method; - return this; - }, - - /** - @public - - Fires an event on the current list of resolved/resolving - handlers within this transition. Useful for firing events - on route hierarchies that haven't fully been entered yet. - - Note: This method is also aliased as `send` - - @param {Boolean} [ignoreFailure=false] a boolean specifying whether unhandled events throw an error - @param {String} name the name of the event to fire - */ - trigger: function (ignoreFailure) { - var args = slice.call(arguments); - if (typeof ignoreFailure === 'boolean') { - args.shift(); - } else { - // Throw errors on unhandled trigger events by default - ignoreFailure = false; - } - trigger(this.router, this.state.handlerInfos.slice(0, this.resolveIndex + 1), ignoreFailure, args); - }, - - /** - @public - - Transitions are aborted and their promises rejected - when redirects occur; this method returns a promise - that will follow any redirects that occur and fulfill - with the value fulfilled by any redirecting transitions - that occur. - - @return {Promise} a promise that fulfills with the same - value that the final redirecting transition fulfills with - */ - followRedirects: function() { - var router = this.router; - return this.promise['catch'](function(reason) { - if (router.activeTransition) { - return router.activeTransition.followRedirects(); - } - return Promise.reject(reason); - }); - }, - - toString: function() { - return "Transition (sequence " + this.sequence + ")"; - }, - - /** - @private - */ - log: function(message) { - log(this.router, this.sequence, message); - } - }; - - // Alias 'trigger' as 'send' - Transition.prototype.send = Transition.prototype.trigger; - - /** - @private - - Logs and returns a TransitionAborted error. - */ - function logAbort(transition) { - log(transition.router, transition.sequence, "detected abort."); - return new TransitionAborted(); - } - - function TransitionAborted(message) { - this.message = (message || "TransitionAborted"); - this.name = "TransitionAborted"; - } - - __exports__.Transition = Transition; - __exports__.logAbort = logAbort; - __exports__.TransitionAborted = TransitionAborted; - }); -enifed("router/utils", - ["exports"], - function(__exports__) { - "use strict"; - var slice = Array.prototype.slice; - - var _isArray; - if (!Array.isArray) { - _isArray = function (x) { - return Object.prototype.toString.call(x) === "[object Array]"; - }; - } else { - _isArray = Array.isArray; - } - - var isArray = _isArray; - __exports__.isArray = isArray; - function merge(hash, other) { - for (var prop in other) { - if (other.hasOwnProperty(prop)) { hash[prop] = other[prop]; } - } - } - - var oCreate = Object.create || function(proto) { - function F() {} - F.prototype = proto; - return new F(); - }; - __exports__.oCreate = oCreate; - /** - @private - - Extracts query params from the end of an array - **/ - function extractQueryParams(array) { - var len = (array && array.length), head, queryParams; - - if(len && len > 0 && array[len - 1] && array[len - 1].hasOwnProperty('queryParams')) { - queryParams = array[len - 1].queryParams; - head = slice.call(array, 0, len - 1); - return [head, queryParams]; - } else { - return [array, null]; - } - } - - __exports__.extractQueryParams = extractQueryParams;/** - @private - - Coerces query param properties and array elements into strings. - **/ - function coerceQueryParamsToString(queryParams) { - for (var key in queryParams) { - if (typeof queryParams[key] === 'number') { - queryParams[key] = '' + queryParams[key]; - } else if (isArray(queryParams[key])) { - for (var i = 0, l = queryParams[key].length; i < l; i++) { - queryParams[key][i] = '' + queryParams[key][i]; - } - } - } - } - /** - @private - */ - function log(router, sequence, msg) { - if (!router.log) { return; } - - if (arguments.length === 3) { - router.log("Transition #" + sequence + ": " + msg); - } else { - msg = sequence; - router.log(msg); - } - } - - __exports__.log = log;function bind(context, fn) { - var boundArgs = arguments; - return function(value) { - var args = slice.call(boundArgs, 2); - args.push(value); - return fn.apply(context, args); - }; - } - - __exports__.bind = bind;function isParam(object) { - return (typeof object === "string" || object instanceof String || typeof object === "number" || object instanceof Number); - } - - - function forEach(array, callback) { - for (var i=0, l=array.length; i=0; i--) { - var handlerInfo = handlerInfos[i], - handler = handlerInfo.handler; - - if (handler.events && handler.events[name]) { - if (handler.events[name].apply(handler, args) === true) { - eventWasHandled = true; - } else { - return; - } - } - } - - if (!eventWasHandled && !ignoreFailure) { - throw new Error("Nothing handled the event '" + name + "'."); - } - } - - __exports__.trigger = trigger;function getChangelist(oldObject, newObject) { - var key; - var results = { - all: {}, - changed: {}, - removed: {} - }; - - merge(results.all, newObject); - - var didChange = false; - coerceQueryParamsToString(oldObject); - coerceQueryParamsToString(newObject); - - // Calculate removals - for (key in oldObject) { - if (oldObject.hasOwnProperty(key)) { - if (!newObject.hasOwnProperty(key)) { - didChange = true; - results.removed[key] = oldObject[key]; - } - } - } - - // Calculate changes - for (key in newObject) { - if (newObject.hasOwnProperty(key)) { - if (isArray(oldObject[key]) && isArray(newObject[key])) { - if (oldObject[key].length !== newObject[key].length) { - results.changed[key] = newObject[key]; - didChange = true; - } else { - for (var i = 0, l = oldObject[key].length; i < l; i++) { - if (oldObject[key][i] !== newObject[key][i]) { - results.changed[key] = newObject[key]; - didChange = true; - } - } - } - } - else { - if (oldObject[key] !== newObject[key]) { - results.changed[key] = newObject[key]; - didChange = true; - } - } - } - } - - return didChange && results; - } - - __exports__.getChangelist = getChangelist;function promiseLabel(label) { - return 'Router: ' + label; - } - - __exports__.promiseLabel = promiseLabel;function subclass(parentConstructor, proto) { - function C(props) { - parentConstructor.call(this, props || {}); - } - C.prototype = oCreate(parentConstructor.prototype); - merge(C.prototype, proto); - return C; - } - - __exports__.subclass = subclass;function resolveHook(obj, hookName) { - if (!obj) { return; } - var underscored = "_" + hookName; - return obj[underscored] && underscored || - obj[hookName] && hookName; - } - - function callHook(obj, hookName) { - var args = slice.call(arguments, 2); - return applyHook(obj, hookName, args); - } - - function applyHook(obj, _hookName, args) { - var hookName = resolveHook(obj, _hookName); - if (hookName) { - return obj[hookName].apply(obj, args); - } - } - - __exports__.merge = merge; - __exports__.slice = slice; - __exports__.isParam = isParam; - __exports__.coerceQueryParamsToString = coerceQueryParamsToString; - __exports__.callHook = callHook; - __exports__.resolveHook = resolveHook; - __exports__.applyHook = applyHook; - }); -enifed("rsvp", - ["./rsvp/promise","./rsvp/events","./rsvp/node","./rsvp/all","./rsvp/all-settled","./rsvp/race","./rsvp/hash","./rsvp/hash-settled","./rsvp/rethrow","./rsvp/defer","./rsvp/config","./rsvp/map","./rsvp/resolve","./rsvp/reject","./rsvp/filter","./rsvp/asap","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - var EventTarget = __dependency2__["default"]; - var denodeify = __dependency3__["default"]; - var all = __dependency4__["default"]; - var allSettled = __dependency5__["default"]; - var race = __dependency6__["default"]; - var hash = __dependency7__["default"]; - var hashSettled = __dependency8__["default"]; - var rethrow = __dependency9__["default"]; - var defer = __dependency10__["default"]; - var config = __dependency11__.config; - var configure = __dependency11__.configure; - var map = __dependency12__["default"]; - var resolve = __dependency13__["default"]; - var reject = __dependency14__["default"]; - var filter = __dependency15__["default"]; - var asap = __dependency16__["default"]; - - config.async = asap; // default async is asap; - var cast = resolve; - function async(callback, arg) { - config.async(callback, arg); - } - - function on() { - config.on.apply(config, arguments); - } - - function off() { - config.off.apply(config, arguments); - } - - // Set up instrumentation through `window.__PROMISE_INTRUMENTATION__` - if (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') { - var callbacks = window['__PROMISE_INSTRUMENTATION__']; - configure('instrument', true); - for (var eventName in callbacks) { - if (callbacks.hasOwnProperty(eventName)) { - on(eventName, callbacks[eventName]); - } - } - } - - __exports__.cast = cast; - __exports__.Promise = Promise; - __exports__.EventTarget = EventTarget; - __exports__.all = all; - __exports__.allSettled = allSettled; - __exports__.race = race; - __exports__.hash = hash; - __exports__.hashSettled = hashSettled; - __exports__.rethrow = rethrow; - __exports__.defer = defer; - __exports__.denodeify = denodeify; - __exports__.configure = configure; - __exports__.on = on; - __exports__.off = off; - __exports__.resolve = resolve; - __exports__.reject = reject; - __exports__.async = async; - __exports__.map = map; - __exports__.filter = filter; - }); -enifed("rsvp.umd", - ["./rsvp"], - function(__dependency1__) { - "use strict"; - var Promise = __dependency1__.Promise; - var allSettled = __dependency1__.allSettled; - var hash = __dependency1__.hash; - var hashSettled = __dependency1__.hashSettled; - var denodeify = __dependency1__.denodeify; - var on = __dependency1__.on; - var off = __dependency1__.off; - var map = __dependency1__.map; - var filter = __dependency1__.filter; - var resolve = __dependency1__.resolve; - var reject = __dependency1__.reject; - var rethrow = __dependency1__.rethrow; - var all = __dependency1__.all; - var defer = __dependency1__.defer; - var EventTarget = __dependency1__.EventTarget; - var configure = __dependency1__.configure; - var race = __dependency1__.race; - var async = __dependency1__.async; - - var RSVP = { - 'race': race, - 'Promise': Promise, - 'allSettled': allSettled, - 'hash': hash, - 'hashSettled': hashSettled, - 'denodeify': denodeify, - 'on': on, - 'off': off, - 'map': map, - 'filter': filter, - 'resolve': resolve, - 'reject': reject, - 'all': all, - 'rethrow': rethrow, - 'defer': defer, - 'EventTarget': EventTarget, - 'configure': configure, - 'async': async - }; - - /* global define:true module:true window: true */ - if (typeof enifed === 'function' && enifed['amd']) { - enifed(function() { return RSVP; }); - } else if (typeof module !== 'undefined' && module['exports']) { - module['exports'] = RSVP; - } else if (typeof this !== 'undefined') { - this['RSVP'] = RSVP; - } - }); -enifed("rsvp/-internal", - ["./utils","./instrument","./config","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var objectOrFunction = __dependency1__.objectOrFunction; - var isFunction = __dependency1__.isFunction; - - var instrument = __dependency2__["default"]; - - var config = __dependency3__.config; - - function withOwnPromise() { - return new TypeError('A promises callback cannot return that same promise.'); - } - - function noop() {} - - var PENDING = void 0; - var FULFILLED = 1; - var REJECTED = 2; - - var GET_THEN_ERROR = new ErrorObject(); - - function getThen(promise) { - try { - return promise.then; - } catch(error) { - GET_THEN_ERROR.error = error; - return GET_THEN_ERROR; - } - } - - function tryThen(then, value, fulfillmentHandler, rejectionHandler) { - try { - then.call(value, fulfillmentHandler, rejectionHandler); - } catch(e) { - return e; - } - } - - function handleForeignThenable(promise, thenable, then) { - config.async(function(promise) { - var sealed = false; - var error = tryThen(then, thenable, function(value) { - if (sealed) { return; } - sealed = true; - if (thenable !== value) { - resolve(promise, value); - } else { - fulfill(promise, value); - } - }, function(reason) { - if (sealed) { return; } - sealed = true; - - reject(promise, reason); - }, 'Settle: ' + (promise._label || ' unknown promise')); - - if (!sealed && error) { - sealed = true; - reject(promise, error); - } - }, promise); - } - - function handleOwnThenable(promise, thenable) { - if (thenable._state === FULFILLED) { - fulfill(promise, thenable._result); - } else if (promise._state === REJECTED) { - reject(promise, thenable._result); - } else { - subscribe(thenable, undefined, function(value) { - if (thenable !== value) { - resolve(promise, value); - } else { - fulfill(promise, value); - } - }, function(reason) { - reject(promise, reason); - }); - } - } - - function handleMaybeThenable(promise, maybeThenable) { - if (maybeThenable.constructor === promise.constructor) { - handleOwnThenable(promise, maybeThenable); - } else { - var then = getThen(maybeThenable); - - if (then === GET_THEN_ERROR) { - reject(promise, GET_THEN_ERROR.error); - } else if (then === undefined) { - fulfill(promise, maybeThenable); - } else if (isFunction(then)) { - handleForeignThenable(promise, maybeThenable, then); - } else { - fulfill(promise, maybeThenable); - } - } - } - - function resolve(promise, value) { - if (promise === value) { - fulfill(promise, value); - } else if (objectOrFunction(value)) { - handleMaybeThenable(promise, value); - } else { - fulfill(promise, value); - } - } - - function publishRejection(promise) { - if (promise._onerror) { - promise._onerror(promise._result); - } - - publish(promise); - } - - function fulfill(promise, value) { - if (promise._state !== PENDING) { return; } - - promise._result = value; - promise._state = FULFILLED; - - if (promise._subscribers.length === 0) { - if (config.instrument) { - instrument('fulfilled', promise); - } - } else { - config.async(publish, promise); - } - } - - function reject(promise, reason) { - if (promise._state !== PENDING) { return; } - promise._state = REJECTED; - promise._result = reason; - - config.async(publishRejection, promise); - } - - function subscribe(parent, child, onFulfillment, onRejection) { - var subscribers = parent._subscribers; - var length = subscribers.length; - - parent._onerror = null; - - subscribers[length] = child; - subscribers[length + FULFILLED] = onFulfillment; - subscribers[length + REJECTED] = onRejection; - - if (length === 0 && parent._state) { - config.async(publish, parent); - } - } - - function publish(promise) { - var subscribers = promise._subscribers; - var settled = promise._state; - - if (config.instrument) { - instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise); - } - - if (subscribers.length === 0) { return; } - - var child, callback, detail = promise._result; - - for (var i = 0; i < subscribers.length; i += 3) { - child = subscribers[i]; - callback = subscribers[i + settled]; - - if (child) { - invokeCallback(settled, child, callback, detail); - } else { - callback(detail); - } - } - - promise._subscribers.length = 0; - } - - function ErrorObject() { - this.error = null; - } - - var TRY_CATCH_ERROR = new ErrorObject(); - - function tryCatch(callback, detail) { - try { - return callback(detail); - } catch(e) { - TRY_CATCH_ERROR.error = e; - return TRY_CATCH_ERROR; - } - } - - function invokeCallback(settled, promise, callback, detail) { - var hasCallback = isFunction(callback), - value, error, succeeded, failed; - - if (hasCallback) { - value = tryCatch(callback, detail); - - if (value === TRY_CATCH_ERROR) { - failed = true; - error = value.error; - value = null; - } else { - succeeded = true; - } - - if (promise === value) { - reject(promise, withOwnPromise()); - return; - } - - } else { - value = detail; - succeeded = true; - } - - if (promise._state !== PENDING) { - // noop - } else if (hasCallback && succeeded) { - resolve(promise, value); - } else if (failed) { - reject(promise, error); - } else if (settled === FULFILLED) { - fulfill(promise, value); - } else if (settled === REJECTED) { - reject(promise, value); - } - } - - function initializePromise(promise, resolver) { - try { - resolver(function resolvePromise(value){ - resolve(promise, value); - }, function rejectPromise(reason) { - reject(promise, reason); - }); - } catch(e) { - reject(promise, e); - } - } - - __exports__.noop = noop; - __exports__.resolve = resolve; - __exports__.reject = reject; - __exports__.fulfill = fulfill; - __exports__.subscribe = subscribe; - __exports__.publish = publish; - __exports__.publishRejection = publishRejection; - __exports__.initializePromise = initializePromise; - __exports__.invokeCallback = invokeCallback; - __exports__.FULFILLED = FULFILLED; - __exports__.REJECTED = REJECTED; - __exports__.PENDING = PENDING; - }); -enifed("rsvp/all-settled", - ["./enumerator","./promise","./utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Enumerator = __dependency1__["default"]; - var makeSettledResult = __dependency1__.makeSettledResult; - var Promise = __dependency2__["default"]; - var o_create = __dependency3__.o_create; - - function AllSettled(Constructor, entries, label) { - this._superConstructor(Constructor, entries, false /* don't abort on reject */, label); - } - - AllSettled.prototype = o_create(Enumerator.prototype); - AllSettled.prototype._superConstructor = Enumerator; - AllSettled.prototype._makeResult = makeSettledResult; - AllSettled.prototype._validationError = function() { - return new Error('allSettled must be called with an array'); - }; - - /** - `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing - a fail-fast method, it waits until all the promises have returned and - shows you all the results. This is useful if you want to handle multiple - promises' failure states together as a set. - - Returns a promise that is fulfilled when all the given promises have been - settled. The return promise is fulfilled with an array of the states of - the promises passed into the `promises` array argument. - - Each state object will either indicate fulfillment or rejection, and - provide the corresponding value or reason. The states will take one of - the following formats: - - ```javascript - { state: 'fulfilled', value: value } - or - { state: 'rejected', reason: reason } - ``` - - Example: - - ```javascript - var promise1 = RSVP.Promise.resolve(1); - var promise2 = RSVP.Promise.reject(new Error('2')); - var promise3 = RSVP.Promise.reject(new Error('3')); - var promises = [ promise1, promise2, promise3 ]; - - RSVP.allSettled(promises).then(function(array){ - // array == [ - // { state: 'fulfilled', value: 1 }, - // { state: 'rejected', reason: Error }, - // { state: 'rejected', reason: Error } - // ] - // Note that for the second item, reason.message will be '2', and for the - // third item, reason.message will be '3'. - }, function(error) { - // Not run. (This block would only be called if allSettled had failed, - // for instance if passed an incorrect argument type.) - }); - ``` - - @method allSettled - @static - @for RSVP - @param {Array} promises - @param {String} label - optional string that describes the promise. - Useful for tooling. - @return {Promise} promise that is fulfilled with an array of the settled - states of the constituent promises. - */ - - __exports__["default"] = function allSettled(entries, label) { - return new AllSettled(Promise, entries, label).promise; - } - }); -enifed("rsvp/all", - ["./promise","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - - /** - This is a convenient alias for `RSVP.Promise.all`. - - @method all - @static - @for RSVP - @param {Array} array Array of promises. - @param {String} label An optional label. This is useful - for tooling. - */ - __exports__["default"] = function all(array, label) { - return Promise.all(array, label); - } - }); -enifed("rsvp/asap", - ["exports"], - function(__exports__) { - "use strict"; - var len = 0; - - __exports__["default"] = function asap(callback, arg) { - queue[len] = callback; - queue[len + 1] = arg; - len += 2; - if (len === 2) { - // If len is 1, that means that we need to schedule an async flush. - // If additional callbacks are queued before the queue is flushed, they - // will be processed by this flush that we are scheduling. - scheduleFlush(); - } - } - - var browserWindow = (typeof window !== 'undefined') ? window : undefined - var browserGlobal = browserWindow || {}; - var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; - - // test for web worker but not in IE10 - var isWorker = typeof Uint8ClampedArray !== 'undefined' && - typeof importScripts !== 'undefined' && - typeof MessageChannel !== 'undefined'; - - // node - function useNextTick() { - return function() { - process.nextTick(flush); - }; - } - - // vertx - function useVertxTimer() { - return function() { - vertxNext(flush); - }; - } - - function useMutationObserver() { - var iterations = 0; - var observer = new BrowserMutationObserver(flush); - var node = document.createTextNode(''); - observer.observe(node, { characterData: true }); - - return function() { - node.data = (iterations = ++iterations % 2); - }; - } - - // web worker - function useMessageChannel() { - var channel = new MessageChannel(); - channel.port1.onmessage = flush; - return function () { - channel.port2.postMessage(0); - }; - } - - function useSetTimeout() { - return function() { - setTimeout(flush, 1); - }; - } - - var queue = new Array(1000); - function flush() { - for (var i = 0; i < len; i+=2) { - var callback = queue[i]; - var arg = queue[i+1]; - - callback(arg); - - queue[i] = undefined; - queue[i+1] = undefined; - } - - len = 0; - } - - function attemptVertex() { - try { - var vertx = eriuqer('vertx'); - var vertxNext = vertx.runOnLoop || vertx.runOnContext; - return useVertxTimer(); - } catch(e) { - return useSetTimeout(); - } - } - - var scheduleFlush; - // Decide what async method to use to triggering processing of queued callbacks: - if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') { - scheduleFlush = useNextTick(); - } else if (BrowserMutationObserver) { - scheduleFlush = useMutationObserver(); - } else if (isWorker) { - scheduleFlush = useMessageChannel(); - } else if (browserWindow === undefined && typeof eriuqer === 'function') { - scheduleFlush = attemptVertex(); - } else { - scheduleFlush = useSetTimeout(); - } - }); -enifed("rsvp/config", - ["./events","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var EventTarget = __dependency1__["default"]; - - var config = { - instrument: false - }; - - EventTarget.mixin(config); - - function configure(name, value) { - if (name === 'onerror') { - // handle for legacy users that expect the actual - // error to be passed to their function added via - // `RSVP.configure('onerror', someFunctionHere);` - config.on('error', value); - return; - } - - if (arguments.length === 2) { - config[name] = value; - } else { - return config[name]; - } - } - - __exports__.config = config; - __exports__.configure = configure; - }); -enifed("rsvp/defer", - ["./promise","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - - /** - `RSVP.defer` returns an object similar to jQuery's `$.Deferred`. - `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s - interface. New code should use the `RSVP.Promise` constructor instead. - - The object returned from `RSVP.defer` is a plain object with three properties: - - * promise - an `RSVP.Promise`. - * reject - a function that causes the `promise` property on this object to - become rejected - * resolve - a function that causes the `promise` property on this object to - become fulfilled. - - Example: - - ```javascript - var deferred = RSVP.defer(); - - deferred.resolve("Success!"); - - defered.promise.then(function(value){ - // value here is "Success!" - }); - ``` - - @method defer - @static - @for RSVP - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Object} - */ - - __exports__["default"] = function defer(label) { - var deferred = { }; - - deferred['promise'] = new Promise(function(resolve, reject) { - deferred['resolve'] = resolve; - deferred['reject'] = reject; - }, label); - - return deferred; - } - }); -enifed("rsvp/enumerator", - ["./utils","./-internal","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var isArray = __dependency1__.isArray; - var isMaybeThenable = __dependency1__.isMaybeThenable; - - var noop = __dependency2__.noop; - var reject = __dependency2__.reject; - var fulfill = __dependency2__.fulfill; - var subscribe = __dependency2__.subscribe; - var FULFILLED = __dependency2__.FULFILLED; - var REJECTED = __dependency2__.REJECTED; - var PENDING = __dependency2__.PENDING; - - function makeSettledResult(state, position, value) { - if (state === FULFILLED) { - return { - state: 'fulfilled', - value: value - }; - } else { - return { - state: 'rejected', - reason: value - }; - } - } - - __exports__.makeSettledResult = makeSettledResult;function Enumerator(Constructor, input, abortOnReject, label) { - this._instanceConstructor = Constructor; - this.promise = new Constructor(noop, label); - this._abortOnReject = abortOnReject; - - if (this._validateInput(input)) { - this._input = input; - this.length = input.length; - this._remaining = input.length; - - this._init(); - - if (this.length === 0) { - fulfill(this.promise, this._result); - } else { - this.length = this.length || 0; - this._enumerate(); - if (this._remaining === 0) { - fulfill(this.promise, this._result); - } - } - } else { - reject(this.promise, this._validationError()); - } - } - - Enumerator.prototype._validateInput = function(input) { - return isArray(input); - }; - - Enumerator.prototype._validationError = function() { - return new Error('Array Methods must be provided an Array'); - }; - - Enumerator.prototype._init = function() { - this._result = new Array(this.length); - }; - - __exports__["default"] = Enumerator; - - Enumerator.prototype._enumerate = function() { - var length = this.length; - var promise = this.promise; - var input = this._input; - - for (var i = 0; promise._state === PENDING && i < length; i++) { - this._eachEntry(input[i], i); - } - }; - - Enumerator.prototype._eachEntry = function(entry, i) { - var c = this._instanceConstructor; - if (isMaybeThenable(entry)) { - if (entry.constructor === c && entry._state !== PENDING) { - entry._onerror = null; - this._settledAt(entry._state, i, entry._result); - } else { - this._willSettleAt(c.resolve(entry), i); - } - } else { - this._remaining--; - this._result[i] = this._makeResult(FULFILLED, i, entry); - } - }; - - Enumerator.prototype._settledAt = function(state, i, value) { - var promise = this.promise; - - if (promise._state === PENDING) { - this._remaining--; - - if (this._abortOnReject && state === REJECTED) { - reject(promise, value); - } else { - this._result[i] = this._makeResult(state, i, value); - } - } - - if (this._remaining === 0) { - fulfill(promise, this._result); - } - }; - - Enumerator.prototype._makeResult = function(state, i, value) { - return value; - }; - - Enumerator.prototype._willSettleAt = function(promise, i) { - var enumerator = this; - - subscribe(promise, undefined, function(value) { - enumerator._settledAt(FULFILLED, i, value); - }, function(reason) { - enumerator._settledAt(REJECTED, i, reason); - }); - }; - }); -enifed("rsvp/events", - ["exports"], - function(__exports__) { - "use strict"; - function indexOf(callbacks, callback) { - for (var i=0, l=callbacks.length; i 1; - }; - - RSVP.filter(promises, filterFn).then(function(result){ - // result is [ 2, 3 ] - }); - ``` - - If any of the `promises` given to `RSVP.filter` are rejected, the first promise - that is rejected will be given as an argument to the returned promise's - rejection handler. For example: - - ```javascript - var promise1 = RSVP.resolve(1); - var promise2 = RSVP.reject(new Error('2')); - var promise3 = RSVP.reject(new Error('3')); - var promises = [ promise1, promise2, promise3 ]; - - var filterFn = function(item){ - return item > 1; - }; - - RSVP.filter(promises, filterFn).then(function(array){ - // Code here never runs because there are rejected promises! - }, function(reason) { - // reason.message === '2' - }); - ``` - - `RSVP.filter` will also wait for any promises returned from `filterFn`. - For instance, you may want to fetch a list of users then return a subset - of those users based on some asynchronous operation: - - ```javascript - - var alice = { name: 'alice' }; - var bob = { name: 'bob' }; - var users = [ alice, bob ]; - - var promises = users.map(function(user){ - return RSVP.resolve(user); - }); - - var filterFn = function(user){ - // Here, Alice has permissions to create a blog post, but Bob does not. - return getPrivilegesForUser(user).then(function(privs){ - return privs.can_create_blog_post === true; - }); - }; - RSVP.filter(promises, filterFn).then(function(users){ - // true, because the server told us only Alice can create a blog post. - users.length === 1; - // false, because Alice is the only user present in `users` - users[0] === bob; - }); - ``` - - @method filter - @static - @for RSVP - @param {Array} promises - @param {Function} filterFn - function to be called on each resolved value to - filter the final results. - @param {String} label optional string describing the promise. Useful for - tooling. - @return {Promise} - */ - __exports__["default"] = function filter(promises, filterFn, label) { - return Promise.all(promises, label).then(function(values) { - if (!isFunction(filterFn)) { - throw new TypeError("You must pass a function as filter's second argument."); - } - - var length = values.length; - var filtered = new Array(length); - - for (var i = 0; i < length; i++) { - filtered[i] = filterFn(values[i]); - } - - return Promise.all(filtered, label).then(function(filtered) { - var results = new Array(length); - var newLength = 0; - - for (var i = 0; i < length; i++) { - if (filtered[i]) { - results[newLength] = values[i]; - newLength++; - } - } - - results.length = newLength; - - return results; - }); - }); - } - }); -enifed("rsvp/hash-settled", - ["./promise","./enumerator","./promise-hash","./utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - var makeSettledResult = __dependency2__.makeSettledResult; - var PromiseHash = __dependency3__["default"]; - var Enumerator = __dependency2__["default"]; - var o_create = __dependency4__.o_create; - - function HashSettled(Constructor, object, label) { - this._superConstructor(Constructor, object, false, label); - } - - HashSettled.prototype = o_create(PromiseHash.prototype); - HashSettled.prototype._superConstructor = Enumerator; - HashSettled.prototype._makeResult = makeSettledResult; - - HashSettled.prototype._validationError = function() { - return new Error('hashSettled must be called with an object'); - }; - - /** - `RSVP.hashSettled` is similar to `RSVP.allSettled`, but takes an object - instead of an array for its `promises` argument. - - Unlike `RSVP.all` or `RSVP.hash`, which implement a fail-fast method, - but like `RSVP.allSettled`, `hashSettled` waits until all the - constituent promises have returned and then shows you all the results - with their states and values/reasons. This is useful if you want to - handle multiple promises' failure states together as a set. - - Returns a promise that is fulfilled when all the given promises have been - settled, or rejected if the passed parameters are invalid. - - The returned promise is fulfilled with a hash that has the same key names as - the `promises` object argument. If any of the values in the object are not - promises, they will be copied over to the fulfilled object and marked with state - 'fulfilled'. - - Example: - - ```javascript - var promises = { - myPromise: RSVP.Promise.resolve(1), - yourPromise: RSVP.Promise.resolve(2), - theirPromise: RSVP.Promise.resolve(3), - notAPromise: 4 - }; - - RSVP.hashSettled(promises).then(function(hash){ - // hash here is an object that looks like: - // { - // myPromise: { state: 'fulfilled', value: 1 }, - // yourPromise: { state: 'fulfilled', value: 2 }, - // theirPromise: { state: 'fulfilled', value: 3 }, - // notAPromise: { state: 'fulfilled', value: 4 } - // } - }); - ``` - - If any of the `promises` given to `RSVP.hash` are rejected, the state will - be set to 'rejected' and the reason for rejection provided. - - Example: - - ```javascript - var promises = { - myPromise: RSVP.Promise.resolve(1), - rejectedPromise: RSVP.Promise.reject(new Error('rejection')), - anotherRejectedPromise: RSVP.Promise.reject(new Error('more rejection')), - }; - - RSVP.hashSettled(promises).then(function(hash){ - // hash here is an object that looks like: - // { - // myPromise: { state: 'fulfilled', value: 1 }, - // rejectedPromise: { state: 'rejected', reason: Error }, - // anotherRejectedPromise: { state: 'rejected', reason: Error }, - // } - // Note that for rejectedPromise, reason.message == 'rejection', - // and for anotherRejectedPromise, reason.message == 'more rejection'. - }); - ``` - - An important note: `RSVP.hashSettled` is intended for plain JavaScript objects that - are just a set of keys and values. `RSVP.hashSettled` will NOT preserve prototype - chains. - - Example: - - ```javascript - function MyConstructor(){ - this.example = RSVP.Promise.resolve('Example'); - } - - MyConstructor.prototype = { - protoProperty: RSVP.Promise.resolve('Proto Property') - }; - - var myObject = new MyConstructor(); - - RSVP.hashSettled(myObject).then(function(hash){ - // protoProperty will not be present, instead you will just have an - // object that looks like: - // { - // example: { state: 'fulfilled', value: 'Example' } - // } - // - // hash.hasOwnProperty('protoProperty'); // false - // 'undefined' === typeof hash.protoProperty - }); - ``` - - @method hashSettled - @for RSVP - @param {Object} promises - @param {String} label optional string that describes the promise. - Useful for tooling. - @return {Promise} promise that is fulfilled when when all properties of `promises` - have been settled. - @static - */ - __exports__["default"] = function hashSettled(object, label) { - return new HashSettled(Promise, object, label).promise; - } - }); -enifed("rsvp/hash", - ["./promise","./promise-hash","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - var PromiseHash = __dependency2__["default"]; - - /** - `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array - for its `promises` argument. - - Returns a promise that is fulfilled when all the given promises have been - fulfilled, or rejected if any of them become rejected. The returned promise - is fulfilled with a hash that has the same key names as the `promises` object - argument. If any of the values in the object are not promises, they will - simply be copied over to the fulfilled object. - - Example: - - ```javascript - var promises = { - myPromise: RSVP.resolve(1), - yourPromise: RSVP.resolve(2), - theirPromise: RSVP.resolve(3), - notAPromise: 4 - }; - - RSVP.hash(promises).then(function(hash){ - // hash here is an object that looks like: - // { - // myPromise: 1, - // yourPromise: 2, - // theirPromise: 3, - // notAPromise: 4 - // } - }); - ```` - - If any of the `promises` given to `RSVP.hash` are rejected, the first promise - that is rejected will be given as the reason to the rejection handler. - - Example: - - ```javascript - var promises = { - myPromise: RSVP.resolve(1), - rejectedPromise: RSVP.reject(new Error('rejectedPromise')), - anotherRejectedPromise: RSVP.reject(new Error('anotherRejectedPromise')), - }; - - RSVP.hash(promises).then(function(hash){ - // Code here never runs because there are rejected promises! - }, function(reason) { - // reason.message === 'rejectedPromise' - }); - ``` - - An important note: `RSVP.hash` is intended for plain JavaScript objects that - are just a set of keys and values. `RSVP.hash` will NOT preserve prototype - chains. - - Example: - - ```javascript - function MyConstructor(){ - this.example = RSVP.resolve('Example'); - } - - MyConstructor.prototype = { - protoProperty: RSVP.resolve('Proto Property') - }; - - var myObject = new MyConstructor(); - - RSVP.hash(myObject).then(function(hash){ - // protoProperty will not be present, instead you will just have an - // object that looks like: - // { - // example: 'Example' - // } - // - // hash.hasOwnProperty('protoProperty'); // false - // 'undefined' === typeof hash.protoProperty - }); - ``` - - @method hash - @static - @for RSVP - @param {Object} promises - @param {String} label optional string that describes the promise. - Useful for tooling. - @return {Promise} promise that is fulfilled when all properties of `promises` - have been fulfilled, or rejected if any of them become rejected. - */ - __exports__["default"] = function hash(object, label) { - return new PromiseHash(Promise, object, label).promise; - } - }); -enifed("rsvp/instrument", - ["./config","./utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var config = __dependency1__.config; - var now = __dependency2__.now; - - var queue = []; - - function scheduleFlush() { - setTimeout(function() { - var entry; - for (var i = 0; i < queue.length; i++) { - entry = queue[i]; - - var payload = entry.payload; - - payload.guid = payload.key + payload.id; - payload.childGuid = payload.key + payload.childId; - if (payload.error) { - payload.stack = payload.error.stack; - } - - config.trigger(entry.name, entry.payload); - } - queue.length = 0; - }, 50); - } - - __exports__["default"] = function instrument(eventName, promise, child) { - if (1 === queue.push({ - name: eventName, - payload: { - key: promise._guidKey, - id: promise._id, - eventName: eventName, - detail: promise._result, - childId: child && child._id, - label: promise._label, - timeStamp: now(), - error: config["instrument-with-stack"] ? new Error(promise._label) : null - }})) { - scheduleFlush(); - } - } - }); -enifed("rsvp/map", - ["./promise","./utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - var isFunction = __dependency2__.isFunction; - - /** - `RSVP.map` is similar to JavaScript's native `map` method, except that it - waits for all promises to become fulfilled before running the `mapFn` on - each item in given to `promises`. `RSVP.map` returns a promise that will - become fulfilled with the result of running `mapFn` on the values the promises - become fulfilled with. - - For example: - - ```javascript - - var promise1 = RSVP.resolve(1); - var promise2 = RSVP.resolve(2); - var promise3 = RSVP.resolve(3); - var promises = [ promise1, promise2, promise3 ]; - - var mapFn = function(item){ - return item + 1; - }; - - RSVP.map(promises, mapFn).then(function(result){ - // result is [ 2, 3, 4 ] - }); - ``` - - If any of the `promises` given to `RSVP.map` are rejected, the first promise - that is rejected will be given as an argument to the returned promise's - rejection handler. For example: - - ```javascript - var promise1 = RSVP.resolve(1); - var promise2 = RSVP.reject(new Error('2')); - var promise3 = RSVP.reject(new Error('3')); - var promises = [ promise1, promise2, promise3 ]; - - var mapFn = function(item){ - return item + 1; - }; - - RSVP.map(promises, mapFn).then(function(array){ - // Code here never runs because there are rejected promises! - }, function(reason) { - // reason.message === '2' - }); - ``` - - `RSVP.map` will also wait if a promise is returned from `mapFn`. For example, - say you want to get all comments from a set of blog posts, but you need - the blog posts first because they contain a url to those comments. - - ```javscript - - var mapFn = function(blogPost){ - // getComments does some ajax and returns an RSVP.Promise that is fulfilled - // with some comments data - return getComments(blogPost.comments_url); - }; - - // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled - // with some blog post data - RSVP.map(getBlogPosts(), mapFn).then(function(comments){ - // comments is the result of asking the server for the comments - // of all blog posts returned from getBlogPosts() - }); - ``` - - @method map - @static - @for RSVP - @param {Array} promises - @param {Function} mapFn function to be called on each fulfilled promise. - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} promise that is fulfilled with the result of calling - `mapFn` on each fulfilled promise or value when they become fulfilled. - The promise will be rejected if any of the given `promises` become rejected. - @static - */ - __exports__["default"] = function map(promises, mapFn, label) { - return Promise.all(promises, label).then(function(values) { - if (!isFunction(mapFn)) { - throw new TypeError("You must pass a function as map's second argument."); - } - - var length = values.length; - var results = new Array(length); - - for (var i = 0; i < length; i++) { - results[i] = mapFn(values[i]); - } - - return Promise.all(results, label); - }); - } - }); -enifed("rsvp/node", - ["./promise","./-internal","./utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - var noop = __dependency2__.noop; - var resolve = __dependency2__.resolve; - var reject = __dependency2__.reject; - var isArray = __dependency3__.isArray; - - function Result() { - this.value = undefined; - } - - var ERROR = new Result(); - var GET_THEN_ERROR = new Result(); - - function getThen(obj) { - try { - return obj.then; - } catch(error) { - ERROR.value= error; - return ERROR; - } - } - - - function tryApply(f, s, a) { - try { - f.apply(s, a); - } catch(error) { - ERROR.value = error; - return ERROR; - } - } - - function makeObject(_, argumentNames) { - var obj = {}; - var name; - var i; - var length = _.length; - var args = new Array(length); - - for (var x = 0; x < length; x++) { - args[x] = _[x]; - } - - for (i = 0; i < argumentNames.length; i++) { - name = argumentNames[i]; - obj[name] = args[i + 1]; - } - - return obj; - } - - function arrayResult(_) { - var length = _.length; - var args = new Array(length - 1); - - for (var i = 1; i < length; i++) { - args[i - 1] = _[i]; - } - - return args; - } - - function wrapThenable(then, promise) { - return { - then: function(onFulFillment, onRejection) { - return then.call(promise, onFulFillment, onRejection); - } - }; - } - - /** - `RSVP.denodeify` takes a 'node-style' function and returns a function that - will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the - browser when you'd prefer to use promises over using callbacks. For example, - `denodeify` transforms the following: - - ```javascript - var fs = require('fs'); - - fs.readFile('myfile.txt', function(err, data){ - if (err) return handleError(err); - handleData(data); - }); - ``` - - into: - - ```javascript - var fs = require('fs'); - var readFile = RSVP.denodeify(fs.readFile); - - readFile('myfile.txt').then(handleData, handleError); - ``` - - If the node function has multiple success parameters, then `denodeify` - just returns the first one: - - ```javascript - var request = RSVP.denodeify(require('request')); - - request('http://example.com').then(function(res) { - // ... - }); - ``` - - However, if you need all success parameters, setting `denodeify`'s - second parameter to `true` causes it to return all success parameters - as an array: - - ```javascript - var request = RSVP.denodeify(require('request'), true); - - request('http://example.com').then(function(result) { - // result[0] -> res - // result[1] -> body - }); - ``` - - Or if you pass it an array with names it returns the parameters as a hash: - - ```javascript - var request = RSVP.denodeify(require('request'), ['res', 'body']); - - request('http://example.com').then(function(result) { - // result.res - // result.body - }); - ``` - - Sometimes you need to retain the `this`: - - ```javascript - var app = require('express')(); - var render = RSVP.denodeify(app.render.bind(app)); - ``` - - The denodified function inherits from the original function. It works in all - environments, except IE 10 and below. Consequently all properties of the original - function are available to you. However, any properties you change on the - denodeified function won't be changed on the original function. Example: - - ```javascript - var request = RSVP.denodeify(require('request')), - cookieJar = request.jar(); // <- Inheritance is used here - - request('http://example.com', {jar: cookieJar}).then(function(res) { - // cookieJar.cookies holds now the cookies returned by example.com - }); - ``` - - Using `denodeify` makes it easier to compose asynchronous operations instead - of using callbacks. For example, instead of: - - ```javascript - var fs = require('fs'); - - fs.readFile('myfile.txt', function(err, data){ - if (err) { ... } // Handle error - fs.writeFile('myfile2.txt', data, function(err){ - if (err) { ... } // Handle error - console.log('done') - }); - }); - ``` - - you can chain the operations together using `then` from the returned promise: - - ```javascript - var fs = require('fs'); - var readFile = RSVP.denodeify(fs.readFile); - var writeFile = RSVP.denodeify(fs.writeFile); - - readFile('myfile.txt').then(function(data){ - return writeFile('myfile2.txt', data); - }).then(function(){ - console.log('done') - }).catch(function(error){ - // Handle error - }); - ``` - - @method denodeify - @static - @for RSVP - @param {Function} nodeFunc a 'node-style' function that takes a callback as - its last argument. The callback expects an error to be passed as its first - argument (if an error occurred, otherwise null), and the value from the - operation as its second argument ('function(err, value){ }'). - @param {Boolean|Array} argumentNames An optional paramter that if set - to `true` causes the promise to fulfill with the callback's success arguments - as an array. This is useful if the node function has multiple success - paramters. If you set this paramter to an array with names, the promise will - fulfill with a hash with these names as keys and the success parameters as - values. - @return {Function} a function that wraps `nodeFunc` to return an - `RSVP.Promise` - @static - */ - __exports__["default"] = function denodeify(nodeFunc, options) { - var fn = function() { - var self = this; - var l = arguments.length; - var args = new Array(l + 1); - var arg; - var promiseInput = false; - - for (var i = 0; i < l; ++i) { - arg = arguments[i]; - - if (!promiseInput) { - // TODO: clean this up - promiseInput = needsPromiseInput(arg); - if (promiseInput === GET_THEN_ERROR) { - var p = new Promise(noop); - reject(p, GET_THEN_ERROR.value); - return p; - } else if (promiseInput && promiseInput !== true) { - arg = wrapThenable(promiseInput, arg); - } - } - args[i] = arg; - } - - var promise = new Promise(noop); - - args[l] = function(err, val) { - if (err) - reject(promise, err); - else if (options === undefined) - resolve(promise, val); - else if (options === true) - resolve(promise, arrayResult(arguments)); - else if (isArray(options)) - resolve(promise, makeObject(arguments, options)); - else - resolve(promise, val); - }; - - if (promiseInput) { - return handlePromiseInput(promise, args, nodeFunc, self); - } else { - return handleValueInput(promise, args, nodeFunc, self); - } - }; - - fn.__proto__ = nodeFunc; - - return fn; - } - - function handleValueInput(promise, args, nodeFunc, self) { - var result = tryApply(nodeFunc, self, args); - if (result === ERROR) { - reject(promise, result.value); - } - return promise; - } - - function handlePromiseInput(promise, args, nodeFunc, self){ - return Promise.all(args).then(function(args){ - var result = tryApply(nodeFunc, self, args); - if (result === ERROR) { - reject(promise, result.value); - } - return promise; - }); - } - - function needsPromiseInput(arg) { - if (arg && typeof arg === 'object') { - if (arg.constructor === Promise) { - return true; - } else { - return getThen(arg); - } - } else { - return false; - } - } - }); -enifed("rsvp/promise-hash", - ["./enumerator","./-internal","./utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Enumerator = __dependency1__["default"]; - var PENDING = __dependency2__.PENDING; - var o_create = __dependency3__.o_create; - - function PromiseHash(Constructor, object, label) { - this._superConstructor(Constructor, object, true, label); - } - - __exports__["default"] = PromiseHash; - - PromiseHash.prototype = o_create(Enumerator.prototype); - PromiseHash.prototype._superConstructor = Enumerator; - PromiseHash.prototype._init = function() { - this._result = {}; - }; - - PromiseHash.prototype._validateInput = function(input) { - return input && typeof input === 'object'; - }; - - PromiseHash.prototype._validationError = function() { - return new Error('Promise.hash must be called with an object'); - }; - - PromiseHash.prototype._enumerate = function() { - var promise = this.promise; - var input = this._input; - var results = []; - - for (var key in input) { - if (promise._state === PENDING && input.hasOwnProperty(key)) { - results.push({ - position: key, - entry: input[key] - }); - } - } - - var length = results.length; - this._remaining = length; - var result; - - for (var i = 0; promise._state === PENDING && i < length; i++) { - result = results[i]; - this._eachEntry(result.entry, result.position); - } - }; - }); -enifed("rsvp/promise", - ["./config","./instrument","./utils","./-internal","./promise/all","./promise/race","./promise/resolve","./promise/reject","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - var config = __dependency1__.config; - var instrument = __dependency2__["default"]; - - var isFunction = __dependency3__.isFunction; - var now = __dependency3__.now; - - var noop = __dependency4__.noop; - var subscribe = __dependency4__.subscribe; - var initializePromise = __dependency4__.initializePromise; - var invokeCallback = __dependency4__.invokeCallback; - var FULFILLED = __dependency4__.FULFILLED; - var REJECTED = __dependency4__.REJECTED; - - var all = __dependency5__["default"]; - var race = __dependency6__["default"]; - var Resolve = __dependency7__["default"]; - var Reject = __dependency8__["default"]; - - var guidKey = 'rsvp_' + now() + '-'; - var counter = 0; - - function needsResolver() { - throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); - } - - function needsNew() { - throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); - } - __exports__["default"] = Promise; - /** - Promise objects represent the eventual result of an asynchronous operation. The - primary way of interacting with a promise is through its `then` method, which - registers callbacks to receive either a promise’s eventual value or the reason - why the promise cannot be fulfilled. - - Terminology - ----------- - - - `promise` is an object or function with a `then` method whose behavior conforms to this specification. - - `thenable` is an object or function that defines a `then` method. - - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). - - `exception` is a value that is thrown using the throw statement. - - `reason` is a value that indicates why a promise was rejected. - - `settled` the final resting state of a promise, fulfilled or rejected. - - A promise can be in one of three states: pending, fulfilled, or rejected. - - Promises that are fulfilled have a fulfillment value and are in the fulfilled - state. Promises that are rejected have a rejection reason and are in the - rejected state. A fulfillment value is never a thenable. - - Promises can also be said to *resolve* a value. If this value is also a - promise, then the original promise's settled state will match the value's - settled state. So a promise that *resolves* a promise that rejects will - itself reject, and a promise that *resolves* a promise that fulfills will - itself fulfill. - - - Basic Usage: - ------------ - - ```js - var promise = new Promise(function(resolve, reject) { - // on success - resolve(value); - - // on failure - reject(reason); - }); - - promise.then(function(value) { - // on fulfillment - }, function(reason) { - // on rejection - }); - ``` - - Advanced Usage: - --------------- - - Promises shine when abstracting away asynchronous interactions such as - `XMLHttpRequest`s. - - ```js - function getJSON(url) { - return new Promise(function(resolve, reject){ - var xhr = new XMLHttpRequest(); - - xhr.open('GET', url); - xhr.onreadystatechange = handler; - xhr.responseType = 'json'; - xhr.setRequestHeader('Accept', 'application/json'); - xhr.send(); - - function handler() { - if (this.readyState === this.DONE) { - if (this.status === 200) { - resolve(this.response); - } else { - reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); - } - } - }; - }); - } - - getJSON('/posts.json').then(function(json) { - // on fulfillment - }, function(reason) { - // on rejection - }); - ``` - - Unlike callbacks, promises are great composable primitives. - - ```js - Promise.all([ - getJSON('/posts'), - getJSON('/comments') - ]).then(function(values){ - values[0] // => postsJSON - values[1] // => commentsJSON - - return values; - }); - ``` - - @class RSVP.Promise - @param {function} resolver - @param {String} label optional string for labeling the promise. - Useful for tooling. - @constructor - */ - function Promise(resolver, label) { - this._id = counter++; - this._label = label; - this._state = undefined; - this._result = undefined; - this._subscribers = []; - - if (config.instrument) { - instrument('created', this); - } - - if (noop !== resolver) { - if (!isFunction(resolver)) { - needsResolver(); - } - - if (!(this instanceof Promise)) { - needsNew(); - } - - initializePromise(this, resolver); - } - } - - Promise.cast = Resolve; // deprecated - Promise.all = all; - Promise.race = race; - Promise.resolve = Resolve; - Promise.reject = Reject; - - Promise.prototype = { - constructor: Promise, - - _guidKey: guidKey, - - _onerror: function (reason) { - config.trigger('error', reason); - }, - - /** - The primary way of interacting with a promise is through its `then` method, - which registers callbacks to receive either a promise's eventual value or the - reason why the promise cannot be fulfilled. - - ```js - findUser().then(function(user){ - // user is available - }, function(reason){ - // user is unavailable, and you are given the reason why - }); - ``` - - Chaining - -------- - - The return value of `then` is itself a promise. This second, 'downstream' - promise is resolved with the return value of the first promise's fulfillment - or rejection handler, or rejected if the handler throws an exception. - - ```js - findUser().then(function (user) { - return user.name; - }, function (reason) { - return 'default name'; - }).then(function (userName) { - // If `findUser` fulfilled, `userName` will be the user's name, otherwise it - // will be `'default name'` - }); - - findUser().then(function (user) { - throw new Error('Found user, but still unhappy'); - }, function (reason) { - throw new Error('`findUser` rejected and we're unhappy'); - }).then(function (value) { - // never reached - }, function (reason) { - // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. - // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. - }); - ``` - If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. - - ```js - findUser().then(function (user) { - throw new PedagogicalException('Upstream error'); - }).then(function (value) { - // never reached - }).then(function (value) { - // never reached - }, function (reason) { - // The `PedgagocialException` is propagated all the way down to here - }); - ``` - - Assimilation - ------------ - - Sometimes the value you want to propagate to a downstream promise can only be - retrieved asynchronously. This can be achieved by returning a promise in the - fulfillment or rejection handler. The downstream promise will then be pending - until the returned promise is settled. This is called *assimilation*. - - ```js - findUser().then(function (user) { - return findCommentsByAuthor(user); - }).then(function (comments) { - // The user's comments are now available - }); - ``` - - If the assimliated promise rejects, then the downstream promise will also reject. - - ```js - findUser().then(function (user) { - return findCommentsByAuthor(user); - }).then(function (comments) { - // If `findCommentsByAuthor` fulfills, we'll have the value here - }, function (reason) { - // If `findCommentsByAuthor` rejects, we'll have the reason here - }); - ``` - - Simple Example - -------------- - - Synchronous Example - - ```javascript - var result; - - try { - result = findResult(); - // success - } catch(reason) { - // failure - } - ``` - - Errback Example - - ```js - findResult(function(result, err){ - if (err) { - // failure - } else { - // success - } - }); - ``` - - Promise Example; - - ```javascript - findResult().then(function(result){ - // success - }, function(reason){ - // failure - }); - ``` - - Advanced Example - -------------- - - Synchronous Example - - ```javascript - var author, books; - - try { - author = findAuthor(); - books = findBooksByAuthor(author); - // success - } catch(reason) { - // failure - } - ``` - - Errback Example - - ```js - - function foundBooks(books) { - - } - - function failure(reason) { - - } - - findAuthor(function(author, err){ - if (err) { - failure(err); - // failure - } else { - try { - findBoooksByAuthor(author, function(books, err) { - if (err) { - failure(err); - } else { - try { - foundBooks(books); - } catch(reason) { - failure(reason); - } - } - }); - } catch(error) { - failure(err); - } - // success - } - }); - ``` - - Promise Example; - - ```javascript - findAuthor(). - then(findBooksByAuthor). - then(function(books){ - // found books - }).catch(function(reason){ - // something went wrong - }); - ``` - - @method then - @param {Function} onFulfilled - @param {Function} onRejected - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} - */ - then: function(onFulfillment, onRejection, label) { - var parent = this; - var state = parent._state; - - if (state === FULFILLED && !onFulfillment || state === REJECTED && !onRejection) { - if (config.instrument) { - instrument('chained', this, this); - } - return this; - } - - parent._onerror = null; - - var child = new this.constructor(noop, label); - var result = parent._result; - - if (config.instrument) { - instrument('chained', parent, child); - } - - if (state) { - var callback = arguments[state - 1]; - config.async(function(){ - invokeCallback(state, child, callback, result); - }); - } else { - subscribe(parent, child, onFulfillment, onRejection); - } - - return child; - }, - - /** - `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same - as the catch block of a try/catch statement. - - ```js - function findAuthor(){ - throw new Error('couldn't find that author'); - } - - // synchronous - try { - findAuthor(); - } catch(reason) { - // something went wrong - } - - // async with promises - findAuthor().catch(function(reason){ - // something went wrong - }); - ``` - - @method catch - @param {Function} onRejection - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} - */ - 'catch': function(onRejection, label) { - return this.then(null, onRejection, label); - }, - - /** - `finally` will be invoked regardless of the promise's fate just as native - try/catch/finally behaves - - Synchronous example: - - ```js - findAuthor() { - if (Math.random() > 0.5) { - throw new Error(); - } - return new Author(); - } - - try { - return findAuthor(); // succeed or fail - } catch(error) { - return findOtherAuther(); - } finally { - // always runs - // doesn't affect the return value - } - ``` - - Asynchronous example: - - ```js - findAuthor().catch(function(reason){ - return findOtherAuther(); - }).finally(function(){ - // author was either found, or not - }); - ``` - - @method finally - @param {Function} callback - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} - */ - 'finally': function(callback, label) { - var constructor = this.constructor; - - return this.then(function(value) { - return constructor.resolve(callback()).then(function(){ - return value; - }); - }, function(reason) { - return constructor.resolve(callback()).then(function(){ - throw reason; - }); - }, label); - } - }; - }); -enifed("rsvp/promise/all", - ["../enumerator","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Enumerator = __dependency1__["default"]; - - /** - `RSVP.Promise.all` accepts an array of promises, and returns a new promise which - is fulfilled with an array of fulfillment values for the passed promises, or - rejected with the reason of the first passed promise to be rejected. It casts all - elements of the passed iterable to promises as it runs this algorithm. - - Example: - - ```javascript - var promise1 = RSVP.resolve(1); - var promise2 = RSVP.resolve(2); - var promise3 = RSVP.resolve(3); - var promises = [ promise1, promise2, promise3 ]; - - RSVP.Promise.all(promises).then(function(array){ - // The array here would be [ 1, 2, 3 ]; - }); - ``` - - If any of the `promises` given to `RSVP.all` are rejected, the first promise - that is rejected will be given as an argument to the returned promises's - rejection handler. For example: - - Example: - - ```javascript - var promise1 = RSVP.resolve(1); - var promise2 = RSVP.reject(new Error("2")); - var promise3 = RSVP.reject(new Error("3")); - var promises = [ promise1, promise2, promise3 ]; - - RSVP.Promise.all(promises).then(function(array){ - // Code here never runs because there are rejected promises! - }, function(error) { - // error.message === "2" - }); - ``` - - @method all - @static - @param {Array} entries array of promises - @param {String} label optional string for labeling the promise. - Useful for tooling. - @return {Promise} promise that is fulfilled when all `promises` have been - fulfilled, or rejected if any of them become rejected. - @static - */ - __exports__["default"] = function all(entries, label) { - return new Enumerator(this, entries, true /* abort on reject */, label).promise; - } - }); -enifed("rsvp/promise/race", - ["../utils","../-internal","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var isArray = __dependency1__.isArray; - - var noop = __dependency2__.noop; - var resolve = __dependency2__.resolve; - var reject = __dependency2__.reject; - var subscribe = __dependency2__.subscribe; - var PENDING = __dependency2__.PENDING; - - /** - `RSVP.Promise.race` returns a new promise which is settled in the same way as the - first passed promise to settle. - - Example: - - ```javascript - var promise1 = new RSVP.Promise(function(resolve, reject){ - setTimeout(function(){ - resolve('promise 1'); - }, 200); - }); - - var promise2 = new RSVP.Promise(function(resolve, reject){ - setTimeout(function(){ - resolve('promise 2'); - }, 100); - }); - - RSVP.Promise.race([promise1, promise2]).then(function(result){ - // result === 'promise 2' because it was resolved before promise1 - // was resolved. - }); - ``` - - `RSVP.Promise.race` is deterministic in that only the state of the first - settled promise matters. For example, even if other promises given to the - `promises` array argument are resolved, but the first settled promise has - become rejected before the other promises became fulfilled, the returned - promise will become rejected: - - ```javascript - var promise1 = new RSVP.Promise(function(resolve, reject){ - setTimeout(function(){ - resolve('promise 1'); - }, 200); - }); - - var promise2 = new RSVP.Promise(function(resolve, reject){ - setTimeout(function(){ - reject(new Error('promise 2')); - }, 100); - }); - - RSVP.Promise.race([promise1, promise2]).then(function(result){ - // Code here never runs - }, function(reason){ - // reason.message === 'promise 2' because promise 2 became rejected before - // promise 1 became fulfilled - }); - ``` - - An example real-world use case is implementing timeouts: - - ```javascript - RSVP.Promise.race([ajax('foo.json'), timeout(5000)]) - ``` - - @method race - @static - @param {Array} promises array of promises to observe - @param {String} label optional string for describing the promise returned. - Useful for tooling. - @return {Promise} a promise which settles in the same way as the first passed - promise to settle. - */ - __exports__["default"] = function race(entries, label) { - /*jshint validthis:true */ - var Constructor = this; - - var promise = new Constructor(noop, label); - - if (!isArray(entries)) { - reject(promise, new TypeError('You must pass an array to race.')); - return promise; - } - - var length = entries.length; - - function onFulfillment(value) { - resolve(promise, value); - } - - function onRejection(reason) { - reject(promise, reason); - } - - for (var i = 0; promise._state === PENDING && i < length; i++) { - subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); - } - - return promise; - } - }); -enifed("rsvp/promise/reject", - ["../-internal","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var noop = __dependency1__.noop; - var _reject = __dependency1__.reject; - - /** - `RSVP.Promise.reject` returns a promise rejected with the passed `reason`. - It is shorthand for the following: - - ```javascript - var promise = new RSVP.Promise(function(resolve, reject){ - reject(new Error('WHOOPS')); - }); - - promise.then(function(value){ - // Code here doesn't run because the promise is rejected! - }, function(reason){ - // reason.message === 'WHOOPS' - }); - ``` - - Instead of writing the above, your code now simply becomes the following: - - ```javascript - var promise = RSVP.Promise.reject(new Error('WHOOPS')); - - promise.then(function(value){ - // Code here doesn't run because the promise is rejected! - }, function(reason){ - // reason.message === 'WHOOPS' - }); - ``` - - @method reject - @static - @param {Any} reason value that the returned promise will be rejected with. - @param {String} label optional string for identifying the returned promise. - Useful for tooling. - @return {Promise} a promise rejected with the given `reason`. - */ - __exports__["default"] = function reject(reason, label) { - /*jshint validthis:true */ - var Constructor = this; - var promise = new Constructor(noop, label); - _reject(promise, reason); - return promise; - } - }); -enifed("rsvp/promise/resolve", - ["../-internal","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var noop = __dependency1__.noop; - var _resolve = __dependency1__.resolve; - - /** - `RSVP.Promise.resolve` returns a promise that will become resolved with the - passed `value`. It is shorthand for the following: - - ```javascript - var promise = new RSVP.Promise(function(resolve, reject){ - resolve(1); - }); - - promise.then(function(value){ - // value === 1 - }); - ``` - - Instead of writing the above, your code now simply becomes the following: - - ```javascript - var promise = RSVP.Promise.resolve(1); - - promise.then(function(value){ - // value === 1 - }); - ``` - - @method resolve - @static - @param {Any} value value that the returned promise will be resolved with - @param {String} label optional string for identifying the returned promise. - Useful for tooling. - @return {Promise} a promise that will become fulfilled with the given - `value` - */ - __exports__["default"] = function resolve(object, label) { - /*jshint validthis:true */ - var Constructor = this; - - if (object && typeof object === 'object' && object.constructor === Constructor) { - return object; - } - - var promise = new Constructor(noop, label); - _resolve(promise, object); - return promise; - } - }); -enifed("rsvp/race", - ["./promise","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - - /** - This is a convenient alias for `RSVP.Promise.race`. - - @method race - @static - @for RSVP - @param {Array} array Array of promises. - @param {String} label An optional label. This is useful - for tooling. - */ - __exports__["default"] = function race(array, label) { - return Promise.race(array, label); - } - }); -enifed("rsvp/reject", - ["./promise","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - - /** - This is a convenient alias for `RSVP.Promise.reject`. - - @method reject - @static - @for RSVP - @param {Any} reason value that the returned promise will be rejected with. - @param {String} label optional string for identifying the returned promise. - Useful for tooling. - @return {Promise} a promise rejected with the given `reason`. - */ - __exports__["default"] = function reject(reason, label) { - return Promise.reject(reason, label); - } - }); -enifed("rsvp/resolve", - ["./promise","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var Promise = __dependency1__["default"]; - - /** - This is a convenient alias for `RSVP.Promise.resolve`. - - @method resolve - @static - @for RSVP - @param {Any} value value that the returned promise will be resolved with - @param {String} label optional string for identifying the returned promise. - Useful for tooling. - @return {Promise} a promise that will become fulfilled with the given - `value` - */ - __exports__["default"] = function resolve(value, label) { - return Promise.resolve(value, label); - } - }); -enifed("rsvp/rethrow", - ["exports"], - function(__exports__) { - "use strict"; - /** - `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event - loop in order to aid debugging. - - Promises A+ specifies that any exceptions that occur with a promise must be - caught by the promises implementation and bubbled to the last handler. For - this reason, it is recommended that you always specify a second rejection - handler function to `then`. However, `RSVP.rethrow` will throw the exception - outside of the promise, so it bubbles up to your console if in the browser, - or domain/cause uncaught exception in Node. `rethrow` will also throw the - error again so the error can be handled by the promise per the spec. - - ```javascript - function throws(){ - throw new Error('Whoops!'); - } - - var promise = new RSVP.Promise(function(resolve, reject){ - throws(); - }); - - promise.catch(RSVP.rethrow).then(function(){ - // Code here doesn't run because the promise became rejected due to an - // error! - }, function (err){ - // handle the error here - }); - ``` - - The 'Whoops' error will be thrown on the next turn of the event loop - and you can watch for it in your console. You can also handle it using a - rejection handler given to `.then` or `.catch` on the returned promise. - - @method rethrow - @static - @for RSVP - @param {Error} reason reason the promise became rejected. - @throws Error - @static - */ - __exports__["default"] = function rethrow(reason) { - setTimeout(function() { - throw reason; - }); - throw reason; - } - }); -enifed("rsvp/utils", - ["exports"], - function(__exports__) { - "use strict"; - function objectOrFunction(x) { - return typeof x === 'function' || (typeof x === 'object' && x !== null); - } - - __exports__.objectOrFunction = objectOrFunction;function isFunction(x) { - return typeof x === 'function'; - } - - __exports__.isFunction = isFunction;function isMaybeThenable(x) { - return typeof x === 'object' && x !== null; - } - - __exports__.isMaybeThenable = isMaybeThenable;var _isArray; - if (!Array.isArray) { - _isArray = function (x) { - return Object.prototype.toString.call(x) === '[object Array]'; - }; - } else { - _isArray = Array.isArray; - } - - var isArray = _isArray; - __exports__.isArray = isArray; - // Date.now is not available in browsers < IE9 - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility - var now = Date.now || function() { return new Date().getTime(); }; - __exports__.now = now; - function F() { } - - var o_create = (Object.create || function (o) { - if (arguments.length > 1) { - throw new Error('Second argument not supported'); - } - if (typeof o !== 'object') { - throw new TypeError('Argument must be an object'); - } - F.prototype = o; - return new F(); - }); - __exports__.o_create = o_create; - }); -requireModule("ember"); - -})(); \ No newline at end of file diff --git a/vendor/assets/javascripts/ember-template-compiler.js b/vendor/assets/javascripts/ember-template-compiler.js index ea26e35aa3..13bb96ffcd 100644 --- a/vendor/assets/javascripts/ember-template-compiler.js +++ b/vendor/assets/javascripts/ember-template-compiler.js @@ -1,29 +1,42 @@ /*! * @overview Ember - JavaScript Application Framework - * @copyright Copyright 2011-2014 Tilde Inc. and contributors + * @copyright Copyright 2011-2015 Tilde Inc. and contributors * Portions Copyright 2006-2011 Strobe Inc. * Portions Copyright 2008-2011 Apple Inc. All rights reserved. * @license Licensed under MIT license * See https://raw.github.com/emberjs/ember.js/master/LICENSE - * @version 1.10.1 + * @version 1.11.3 */ (function() { -var define, requireModule, require, requirejs, Ember; +var enifed, requireModule, eriuqer, requirejs, Ember; +var mainContext = this; (function() { + Ember = this.Ember = this.Ember || {}; if (typeof Ember === 'undefined') { Ember = {}; }; function UNDEFINED() { } if (typeof Ember.__loader === 'undefined') { - var registry = {}, seen = {}; + var registry = {}; + var seen = {}; - define = function(name, deps, callback) { - registry[name] = { deps: deps, callback: callback }; + enifed = function(name, deps, callback) { + var value = { }; + + if (!callback) { + value.deps = []; + value.callback = deps; + } else { + value.deps = deps; + value.callback = callback; + } + + registry[name] = value; }; - requirejs = require = requireModule = function(name) { + requirejs = eriuqer = requireModule = function(name) { var s = seen[name]; if (s !== undefined) { return seen[name]; } @@ -65,9 +78,13 @@ var define, requireModule, require, requirejs, Ember; for (var i=0, l=parts.length; i 1) { - this.opcode('shareElement', ++this.elementNum); - this.element = null; // Set element to null so we don't cache it twice - } + // If our parent reference will be used more than once, cache its reference. + if (mustacheCount > 1) { + this.opcode('shareElement', ++this.elementNum); + this.element = null; // Set element to null so we don't cache it twice } + var isElementChecked = detectIsElementChecked(element); if (blankChildTextNodes.length > 0 || isElementChecked) { this.opcode( 'repairClonedNode', @@ -1304,23 +1334,42 @@ define("htmlbars-compiler/hydration-opcode-compiler", this.currentDOMChildIndex = -1; forEach(element.attributes, this.attribute, this); - forEach(element.helpers, this.elementHelper, this); + forEach(element.modifiers, this.elementModifier, this); }; - HydrationOpcodeCompiler.prototype.closeElement = function(element, pos, len, isSingleRoot) { + HydrationOpcodeCompiler.prototype.closeElement = function() { distributeMorphs(this.morphs, this.opcodes); - if (!isSingleRoot) { this.opcode('popParent'); } + this.opcode('popParent'); this.currentDOMChildIndex = this.paths.pop(); }; - HydrationOpcodeCompiler.prototype.block = function(block, childIndex, childrenLength) { - var sexpr = block.sexpr; - - var currentDOMChildIndex = this.currentDOMChildIndex; - var start = (currentDOMChildIndex < 0) ? null : currentDOMChildIndex; - var end = (childIndex === childrenLength - 1) ? null : currentDOMChildIndex + 1; + HydrationOpcodeCompiler.prototype.mustache = function(mustache, childIndex, childCount) { + this.pushMorphPlaceholderNode(childIndex, childCount); + + var sexpr = mustache.sexpr; var morphNum = this.morphNum++; + var start = this.currentDOMChildIndex; + var end = this.currentDOMChildIndex; + this.morphs.push([morphNum, this.paths.slice(), start, end, mustache.escaped]); + + if (isHelper(sexpr)) { + prepareSexpr(this, sexpr); + this.opcode('printInlineHook', morphNum); + } else { + preparePath(this, sexpr.path); + this.opcode('printContentHook', morphNum); + } + }; + + HydrationOpcodeCompiler.prototype.block = function(block, childIndex, childCount) { + this.pushMorphPlaceholderNode(childIndex, childCount); + + var sexpr = block.sexpr; + + var morphNum = this.morphNum++; + var start = this.currentDOMChildIndex; + var end = this.currentDOMChildIndex; this.morphs.push([morphNum, this.paths.slice(), start, end, true]); var templateId = this.templateId++; @@ -1330,15 +1379,15 @@ define("htmlbars-compiler/hydration-opcode-compiler", this.opcode('printBlockHook', morphNum, templateId, inverseId); }; - HydrationOpcodeCompiler.prototype.component = function(component, childIndex, childrenLength) { - var currentDOMChildIndex = this.currentDOMChildIndex; + HydrationOpcodeCompiler.prototype.component = function(component, childIndex, childCount) { + this.pushMorphPlaceholderNode(childIndex, childCount); + var program = component.program || {}; var blockParams = program.blockParams || []; - var start = (currentDOMChildIndex < 0 ? null : currentDOMChildIndex), - end = (childIndex === childrenLength - 1 ? null : currentDOMChildIndex + 1); - var morphNum = this.morphNum++; + var start = this.currentDOMChildIndex; + var end = this.currentDOMChildIndex; this.morphs.push([morphNum, this.paths.slice(), start, end, true]); var attrs = component.attributes; @@ -1392,8 +1441,8 @@ define("htmlbars-compiler/hydration-opcode-compiler", this.opcode('printAttributeHook', attrMorphNum, this.elementNum); }; - HydrationOpcodeCompiler.prototype.elementHelper = function(sexpr) { - prepareSexpr(this, sexpr); + HydrationOpcodeCompiler.prototype.elementModifier = function(modifier) { + prepareSexpr(this, modifier.sexpr); // If we have a helper in a node, and this element has not been cached, cache it if (this.element !== null) { @@ -1404,23 +1453,16 @@ define("htmlbars-compiler/hydration-opcode-compiler", this.opcode('printElementHook', this.elementNum); }; - HydrationOpcodeCompiler.prototype.mustache = function(mustache, childIndex, childrenLength) { - var sexpr = mustache.sexpr; - var currentDOMChildIndex = this.currentDOMChildIndex; - - var start = currentDOMChildIndex, - end = (childIndex === childrenLength - 1 ? -1 : currentDOMChildIndex + 1); - - var morphNum = this.morphNum++; - this.morphs.push([morphNum, this.paths.slice(), start, end, mustache.escaped]); - - if (isHelper(sexpr)) { - prepareSexpr(this, sexpr); - this.opcode('printInlineHook', morphNum); - } else { - preparePath(this, sexpr.path); - this.opcode('printContentHook', morphNum); + HydrationOpcodeCompiler.prototype.pushMorphPlaceholderNode = function(childIndex, childCount) { + if (this.paths.length === 0) { + if (childIndex === 0) { + this.opcode('openBoundary'); + } + if (childIndex === childCount - 1) { + this.opcode('closeBoundary'); + } } + this.comment(); }; HydrationOpcodeCompiler.prototype.SubExpression = function(sexpr) { @@ -1499,7 +1541,7 @@ define("htmlbars-compiler/hydration-opcode-compiler", morphs.length = 0; } }); -define("htmlbars-compiler/template-compiler", +enifed("htmlbars-compiler/template-compiler", ["./fragment-opcode-compiler","./fragment-javascript-compiler","./hydration-opcode-compiler","./hydration-javascript-compiler","./template-visitor","./utils","../htmlbars-util/quoting","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { "use strict"; @@ -1513,6 +1555,7 @@ define("htmlbars-compiler/template-compiler", function TemplateCompiler(options) { this.options = options || {}; + this.revision = this.options.revision || "HTMLBars@v0.11.2"; this.fragmentOpcodeCompiler = new FragmentOpcodeCompiler(); this.fragmentCompiler = new FragmentJavaScriptCompiler(); this.hydrationOpcodeCompiler = new HydrationOpcodeCompiler(); @@ -1598,6 +1641,7 @@ define("htmlbars-compiler/template-compiler", this.getChildTemplateVars(indent + ' ') + indent+' return {\n' + indent+' isHTMLBars: true,\n' + + indent+' revision: "' + this.revision + '",\n' + indent+' blockParams: ' + blockParams.length + ',\n' + indent+' cachedFragment: null,\n' + indent+' hasRendered: false,\n' + @@ -1641,14 +1685,14 @@ define("htmlbars-compiler/template-compiler", this.hydrationOpcodeCompiler.closeElement(element, i, l, r); }; - TemplateCompiler.prototype.component = function(component, i, l) { - this.fragmentOpcodeCompiler.component(component, i, l); - this.hydrationOpcodeCompiler.component(component, i, l); + TemplateCompiler.prototype.component = function(component, i, l, s) { + this.fragmentOpcodeCompiler.component(component, i, l, s); + this.hydrationOpcodeCompiler.component(component, i, l, s); }; - TemplateCompiler.prototype.block = function(block, i, l) { - this.fragmentOpcodeCompiler.block(block, i, l); - this.hydrationOpcodeCompiler.block(block, i, l); + TemplateCompiler.prototype.block = function(block, i, l, s) { + this.fragmentOpcodeCompiler.block(block, i, l, s); + this.hydrationOpcodeCompiler.block(block, i, l, s); }; TemplateCompiler.prototype.text = function(string, i, l, r) { @@ -1661,16 +1705,16 @@ define("htmlbars-compiler/template-compiler", this.hydrationOpcodeCompiler.comment(string, i, l, r); }; - TemplateCompiler.prototype.mustache = function (mustache, i, l) { - this.fragmentOpcodeCompiler.mustache(mustache, i, l); - this.hydrationOpcodeCompiler.mustache(mustache, i, l); + TemplateCompiler.prototype.mustache = function (mustache, i, l, s) { + this.fragmentOpcodeCompiler.mustache(mustache, i, l, s); + this.hydrationOpcodeCompiler.mustache(mustache, i, l, s); }; TemplateCompiler.prototype.setNamespace = function(namespace) { this.fragmentOpcodeCompiler.setNamespace(namespace); }; }); -define("htmlbars-compiler/template-visitor", +enifed("htmlbars-compiler/template-visitor", ["exports"], function(__exports__) { "use strict"; @@ -1781,19 +1825,17 @@ define("htmlbars-compiler/template-visitor", TemplateVisitor.prototype.ElementNode = function(element) { var parentFrame = this.getCurrentFrame(); var elementFrame = this.pushFrame(); - var parentNode = parentFrame.parentNode; elementFrame.parentNode = element; elementFrame.children = element.children; elementFrame.childCount = element.children.length; - elementFrame.mustacheCount += element.helpers.length; + elementFrame.mustacheCount += element.modifiers.length; elementFrame.blankChildTextNodes = []; var actionArgs = [ element, parentFrame.childIndex, - parentFrame.childCount, - parentNode.type === 'Program' && parentFrame.childCount === 1 + parentFrame.childCount ]; elementFrame.actions.push(['closeElement', actionArgs]); @@ -1825,11 +1867,10 @@ define("htmlbars-compiler/template-visitor", TemplateVisitor.prototype.TextNode = function(text) { var frame = this.getCurrentFrame(); - var isSingleRoot = frame.parentNode.type === 'Program' && frame.childCount === 1; if (text.chars === '') { frame.blankChildTextNodes.push(domIndexOf(frame.children, text)); } - frame.actions.push(['text', [text, frame.childIndex, frame.childCount, isSingleRoot]]); + frame.actions.push(['text', [text, frame.childIndex, frame.childCount]]); }; TemplateVisitor.prototype.BlockStatement = function(node) { @@ -1860,9 +1901,7 @@ define("htmlbars-compiler/template-visitor", TemplateVisitor.prototype.CommentStatement = function(text) { var frame = this.getCurrentFrame(); - var isSingleRoot = frame.parentNode.type === 'Program' && frame.childCount === 1; - - frame.actions.push(['comment', [text, frame.childIndex, frame.childCount, isSingleRoot]]); + frame.actions.push(['comment', [text, frame.childIndex, frame.childCount]]); }; TemplateVisitor.prototype.MustacheStatement = function(mustache) { @@ -1912,7 +1951,7 @@ define("htmlbars-compiler/template-visitor", return -1; } }); -define("htmlbars-compiler/utils", +enifed("htmlbars-compiler/utils", ["exports"], function(__exports__) { "use strict"; @@ -1930,7 +1969,160 @@ define("htmlbars-compiler/utils", __exports__.processOpcodes = processOpcodes; }); -define("htmlbars-syntax", +enifed("htmlbars-runtime", + ["htmlbars-runtime/hooks","htmlbars-runtime/helpers","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var hooks = __dependency1__["default"]; + var helpers = __dependency2__["default"]; + + __exports__.hooks = hooks; + __exports__.helpers = helpers; + }); +enifed("htmlbars-runtime/helpers", + ["exports"], + function(__exports__) { + "use strict"; + function partial(params, hash, options, env) { + var template = env.partials[params[0]]; + return template.render(this, env, options.morph.contextualElement); + } + + __exports__.partial = partial;__exports__["default"] = { + partial: partial + }; + }); +enifed("htmlbars-runtime/hooks", + ["exports"], + function(__exports__) { + "use strict"; + function block(env, morph, context, path, params, hash, template, inverse) { + var options = { + morph: morph, + template: template, + inverse: inverse + }; + + var helper = lookupHelper(env, context, path); + var value = helper.call(context, params, hash, options, env); + + morph.setContent(value); + } + + __exports__.block = block;function inline(env, morph, context, path, params, hash) { + var helper = lookupHelper(env, context, path); + var value = helper.call(context, params, hash, { morph: morph }, env); + + morph.setContent(value); + } + + __exports__.inline = inline;function content(env, morph, context, path) { + var helper = lookupHelper(env, context, path); + + var value; + if (helper) { + value = helper.call(context, [], {}, { morph: morph }, env); + } else { + value = get(env, context, path); + } + + morph.setContent(value); + } + + __exports__.content = content;function element(env, domElement, context, path, params, hash) { + var helper = lookupHelper(env, context, path); + if (helper) { + helper.call(context, params, hash, { element: domElement }, env); + } + } + + __exports__.element = element;function attribute(env, attrMorph, domElement, name, value) { + attrMorph.setContent(value); + } + + __exports__.attribute = attribute;function subexpr(env, context, helperName, params, hash) { + var helper = lookupHelper(env, context, helperName); + if (helper) { + return helper.call(context, params, hash, {}, env); + } else { + return get(env, context, helperName); + } + } + + __exports__.subexpr = subexpr;function get(env, context, path) { + if (path === '') { + return context; + } + + var keys = path.split('.'); + var value = context; + for (var i = 0; i < keys.length; i++) { + if (value) { + value = value[keys[i]]; + } else { + break; + } + } + return value; + } + + __exports__.get = get;function set(env, context, name, value) { + context[name] = value; + } + + __exports__.set = set;function component(env, morph, context, tagName, attrs, template) { + var helper = lookupHelper(env, context, tagName); + + var value; + if (helper) { + var options = { + morph: morph, + template: template + }; + + value = helper.call(context, [], attrs, options, env); + } else { + value = componentFallback(env, morph, context, tagName, attrs, template); + } + + morph.setContent(value); + } + + __exports__.component = component;function concat(env, params) { + var value = ""; + for (var i = 0, l = params.length; i < l; i++) { + value += params[i]; + } + return value; + } + + __exports__.concat = concat;function componentFallback(env, morph, context, tagName, attrs, template) { + var element = env.dom.createElement(tagName); + for (var name in attrs) { + element.setAttribute(name, attrs[name]); + } + element.appendChild(template.render(context, env, morph.contextualElement)); + return element; + } + + function lookupHelper(env, context, helperName) { + return env.helpers[helperName]; + } + + __exports__["default"] = { + content: content, + block: block, + inline: inline, + component: component, + element: element, + attribute: attribute, + subexpr: subexpr, + concat: concat, + get: get, + set: set + }; + }); +enifed("htmlbars-syntax", ["./htmlbars-syntax/walker","./htmlbars-syntax/builders","./htmlbars-syntax/parser","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; @@ -1942,7 +2134,7 @@ define("htmlbars-syntax", __exports__.builders = builders; __exports__.parse = parse; }); -define("htmlbars-syntax/builders", +enifed("htmlbars-syntax/builders", ["exports"], function(__exports__) { "use strict"; @@ -1980,22 +2172,28 @@ define("htmlbars-syntax/builders", }; } - __exports__.buildComment = buildComment; - function buildConcat(parts) { + __exports__.buildComment = buildComment;function buildConcat(parts) { return { type: "ConcatStatement", parts: parts || [] }; } - __exports__.buildConcat = buildConcat;// Nodes + __exports__.buildConcat = buildConcat;function buildElementModifier(sexpr) { + return { + type: "ElementModifierStatement", + sexpr: sexpr + }; + } - function buildElement(tag, attributes, helpers, children) { + __exports__.buildElementModifier = buildElementModifier;// Nodes + + function buildElement(tag, attributes, modifiers, children) { return { type: "ElementNode", tag: tag, attributes: attributes || [], - helpers: helpers || [], + modifiers: modifiers || [], children: children || [] }; } @@ -2098,6 +2296,7 @@ define("htmlbars-syntax/builders", partial: buildPartial, comment: buildComment, element: buildElement, + elementModifier: buildElementModifier, component: buildComponent, attr: buildAttr, text: buildText, @@ -2112,7 +2311,7 @@ define("htmlbars-syntax/builders", program: buildProgram }; }); -define("htmlbars-syntax/handlebars/compiler/ast", +enifed("htmlbars-syntax/handlebars/compiler/ast", ["../exception","exports"], function(__dependency1__, __exports__) { "use strict"; @@ -2232,7 +2431,7 @@ define("htmlbars-syntax/handlebars/compiler/ast", // most modify the object to operate properly. __exports__["default"] = AST; }); -define("htmlbars-syntax/handlebars/compiler/base", +enifed("htmlbars-syntax/handlebars/compiler/base", ["./parser","./ast","./whitespace-control","./helpers","../utils","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; @@ -2264,7 +2463,7 @@ define("htmlbars-syntax/handlebars/compiler/base", __exports__.parse = parse; }); -define("htmlbars-syntax/handlebars/compiler/helpers", +enifed("htmlbars-syntax/handlebars/compiler/helpers", ["../exception","exports"], function(__dependency1__, __exports__) { "use strict"; @@ -2385,7 +2584,7 @@ define("htmlbars-syntax/handlebars/compiler/helpers", __exports__.prepareBlock = prepareBlock; }); -define("htmlbars-syntax/handlebars/compiler/parser", +enifed("htmlbars-syntax/handlebars/compiler/parser", ["exports"], function(__exports__) { "use strict"; @@ -2921,7 +3120,7 @@ define("htmlbars-syntax/handlebars/compiler/parser", })();__exports__["default"] = handlebars; /* jshint ignore:end */ }); -define("htmlbars-syntax/handlebars/compiler/visitor", +enifed("htmlbars-syntax/handlebars/compiler/visitor", ["exports"], function(__exports__) { "use strict"; @@ -2992,7 +3191,7 @@ define("htmlbars-syntax/handlebars/compiler/visitor", __exports__["default"] = Visitor; }); -define("htmlbars-syntax/handlebars/compiler/whitespace-control", +enifed("htmlbars-syntax/handlebars/compiler/whitespace-control", ["./visitor","exports"], function(__dependency1__, __exports__) { "use strict"; @@ -3207,7 +3406,7 @@ define("htmlbars-syntax/handlebars/compiler/whitespace-control", __exports__["default"] = WhitespaceControl; }); -define("htmlbars-syntax/handlebars/exception", +enifed("htmlbars-syntax/handlebars/exception", ["exports"], function(__exports__) { "use strict"; @@ -3242,7 +3441,7 @@ define("htmlbars-syntax/handlebars/exception", __exports__["default"] = Exception; }); -define("htmlbars-syntax/handlebars/safe-string", +enifed("htmlbars-syntax/handlebars/safe-string", ["exports"], function(__exports__) { "use strict"; @@ -3257,7 +3456,7 @@ define("htmlbars-syntax/handlebars/safe-string", __exports__["default"] = SafeString; }); -define("htmlbars-syntax/handlebars/utils", +enifed("htmlbars-syntax/handlebars/utils", ["./safe-string","exports"], function(__dependency1__, __exports__) { "use strict"; @@ -3349,7 +3548,7 @@ define("htmlbars-syntax/handlebars/utils", __exports__.appendContextPath = appendContextPath; }); -define("htmlbars-syntax/node-handlers", +enifed("htmlbars-syntax/node-handlers", ["./builders","../htmlbars-util/array-utils","./utils","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; @@ -3358,7 +3557,6 @@ define("htmlbars-syntax/node-handlers", var buildHash = __dependency1__.buildHash; var forEach = __dependency2__.forEach; var appendChild = __dependency3__.appendChild; - var postprocessProgram = __dependency3__.postprocessProgram; var nodeHandlers = { @@ -3377,8 +3575,6 @@ define("htmlbars-syntax/node-handlers", this.acceptToken(this.tokenizer.tokenizeEOF()); - postprocessProgram(node); - // Ensure that that the element stack is balanced properly. var poppedNode = this.elementStack.pop(); if (poppedNode !== node) { @@ -3515,7 +3711,7 @@ define("htmlbars-syntax/node-handlers", __exports__["default"] = nodeHandlers; }); -define("htmlbars-syntax/parser", +enifed("htmlbars-syntax/parser", ["./handlebars/compiler/base","./tokenizer","../simple-html-tokenizer/entity-parser","../simple-html-tokenizer/char-refs/full","./node-handlers","./token-handlers","../htmlbars-syntax","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { "use strict"; @@ -3622,7 +3818,7 @@ define("htmlbars-syntax/parser", return string.join('\n'); }; }); -define("htmlbars-syntax/token-handlers", +enifed("htmlbars-syntax/token-handlers", ["../htmlbars-util/array-utils","./builders","./utils","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; @@ -3634,7 +3830,6 @@ define("htmlbars-syntax/token-handlers", var buildText = __dependency2__.buildText; var appendChild = __dependency3__.appendChild; var parseComponentBlockParams = __dependency3__.parseComponentBlockParams; - var postprocessProgram = __dependency3__.postprocessProgram; // The HTML elements in this list are speced by // http://www.w3.org/TR/html-markup/syntax.html#syntax-elements, @@ -3663,7 +3858,7 @@ define("htmlbars-syntax/token-handlers", }, StartTag: function(tag) { - var element = buildElement(tag.tagName, tag.attributes, tag.helpers || [], []); + var element = buildElement(tag.tagName, tag.attributes, tag.modifiers || [], []); element.loc = { start: { line: tag.firstLine, column: tag.firstColumn}, end: { line: null, column: null} @@ -3689,20 +3884,20 @@ define("htmlbars-syntax/token-handlers", switch(tokenizer.state) { // Tag helpers case "tagName": - tokenizer.addTagHelper(mustache.sexpr); + tokenizer.addElementModifier(mustache); tokenizer.state = "beforeAttributeName"; return; case "beforeAttributeName": - tokenizer.addTagHelper(mustache.sexpr); + tokenizer.addElementModifier(mustache); return; case "attributeName": case "afterAttributeName": tokenizer.finalizeAttributeValue(); - tokenizer.addTagHelper(mustache.sexpr); + tokenizer.addElementModifier(mustache); tokenizer.state = "beforeAttributeName"; return; case "afterAttributeValueQuoted": - tokenizer.addTagHelper(mustache.sexpr); + tokenizer.addElementModifier(mustache); tokenizer.state = "beforeAttributeName"; return; @@ -3737,7 +3932,6 @@ define("htmlbars-syntax/token-handlers", } else { var program = buildProgram(element.children); parseComponentBlockParams(element, program); - postprocessProgram(program); var component = buildComponent(element.tag, element.attributes, program); appendChild(parent, component); } @@ -3769,7 +3963,7 @@ define("htmlbars-syntax/token-handlers", __exports__["default"] = tokenHandlers; }); -define("htmlbars-syntax/tokenizer", +enifed("htmlbars-syntax/tokenizer", ["../simple-html-tokenizer","./utils","../htmlbars-util/array-utils","./builders","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; @@ -3830,9 +4024,13 @@ define("htmlbars-syntax/tokenizer", } }; - Tokenizer.prototype.addTagHelper = function(helper) { - var helpers = this.token.helpers = this.token.helpers || []; - helpers.push(helper); + Tokenizer.prototype.addElementModifier = function(mustache) { + if (!this.token.modifiers) { + this.token.modifiers = []; + } + + var modifier = builders.elementModifier(mustache.sexpr); + this.token.modifiers.push(modifier); }; function prepareAttributeValue(attr) { @@ -3873,12 +4071,11 @@ define("htmlbars-syntax/tokenizer", __exports__.unwrapMustache = unwrapMustache;__exports__.Tokenizer = Tokenizer; }); -define("htmlbars-syntax/utils", - ["./builders","../htmlbars-util/array-utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { +enifed("htmlbars-syntax/utils", + ["../htmlbars-util/array-utils","exports"], + function(__dependency1__, __exports__) { "use strict"; - var buildText = __dependency1__.buildText; - var indexOfArray = __dependency2__.indexOfArray; + var indexOfArray = __dependency1__.indexOfArray; // Regex to validate the identifier for block parameters. // Based on the ID validation regex in Handlebars. @@ -3925,26 +4122,7 @@ define("htmlbars-syntax/utils", } } - __exports__.parseComponentBlockParams = parseComponentBlockParams;// Adds an empty text node at the beginning and end of a program. - // The empty text nodes *between* nodes are handled elsewhere. - - function postprocessProgram(program) { - var body = program.body; - - if (body.length === 0) { - return; - } - - if (usesMorph(body[0])) { - body.unshift(buildText('')); - } - - if (usesMorph(body[body.length-1])) { - body.push(buildText('')); - } - } - - __exports__.postprocessProgram = postprocessProgram;function childrenFor(node) { + __exports__.parseComponentBlockParams = parseComponentBlockParams;function childrenFor(node) { if (node.type === 'Program') { return node.body; } @@ -3953,23 +4131,8 @@ define("htmlbars-syntax/utils", } } - __exports__.childrenFor = childrenFor;function usesMorph(node) { - return node.type === 'MustacheStatement' || - node.type === 'BlockStatement' || - node.type === 'ComponentNode'; - } - - __exports__.usesMorph = usesMorph;function appendChild(parent, node) { - var children = childrenFor(parent); - - var len = children.length, last; - if (len > 0) { - last = children[len-1]; - if (usesMorph(last) && usesMorph(node)) { - children.push(buildText('')); - } - } - children.push(node); + __exports__.childrenFor = childrenFor;function appendChild(parent, node) { + childrenFor(parent).push(node); } __exports__.appendChild = appendChild;function isHelper(sexpr) { @@ -3979,7 +4142,7 @@ define("htmlbars-syntax/utils", __exports__.isHelper = isHelper; }); -define("htmlbars-syntax/walker", +enifed("htmlbars-syntax/walker", ["exports"], function(__exports__) { "use strict"; @@ -4038,7 +4201,7 @@ define("htmlbars-syntax/walker", } }; }); -define("htmlbars-test-helpers", +enifed("htmlbars-test-helpers", ["exports"], function(__exports__) { "use strict"; @@ -4150,7 +4313,7 @@ define("htmlbars-test-helpers", } __exports__.createObject = createObject; }); -define("htmlbars-util", +enifed("htmlbars-util", ["./htmlbars-util/safe-string","./htmlbars-util/handlebars/utils","./htmlbars-util/namespaces","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; @@ -4162,7 +4325,7 @@ define("htmlbars-util", __exports__.escapeExpression = escapeExpression; __exports__.getAttrNamespace = getAttrNamespace; }); -define("htmlbars-util/array-utils", +enifed("htmlbars-util/array-utils", ["exports"], function(__exports__) { "use strict"; @@ -4214,7 +4377,7 @@ define("htmlbars-util/array-utils", var indexOfArray = getIdx; __exports__.indexOfArray = indexOfArray; }); -define("htmlbars-util/handlebars/safe-string", +enifed("htmlbars-util/handlebars/safe-string", ["exports"], function(__exports__) { "use strict"; @@ -4229,7 +4392,7 @@ define("htmlbars-util/handlebars/safe-string", __exports__["default"] = SafeString; }); -define("htmlbars-util/handlebars/utils", +enifed("htmlbars-util/handlebars/utils", ["./safe-string","exports"], function(__dependency1__, __exports__) { "use strict"; @@ -4321,7 +4484,7 @@ define("htmlbars-util/handlebars/utils", __exports__.appendContextPath = appendContextPath; }); -define("htmlbars-util/namespaces", +enifed("htmlbars-util/namespaces", ["exports"], function(__exports__) { "use strict"; @@ -4348,7 +4511,7 @@ define("htmlbars-util/namespaces", __exports__.getAttrNamespace = getAttrNamespace; }); -define("htmlbars-util/object-utils", +enifed("htmlbars-util/object-utils", ["exports"], function(__exports__) { "use strict"; @@ -4362,7 +4525,7 @@ define("htmlbars-util/object-utils", __exports__.merge = merge; }); -define("htmlbars-util/quoting", +enifed("htmlbars-util/quoting", ["exports"], function(__exports__) { "use strict"; @@ -4401,7 +4564,7 @@ define("htmlbars-util/quoting", __exports__.repeat = repeat; }); -define("htmlbars-util/safe-string", +enifed("htmlbars-util/safe-string", ["./handlebars/safe-string","exports"], function(__dependency1__, __exports__) { "use strict"; @@ -4409,7 +4572,7 @@ define("htmlbars-util/safe-string", __exports__["default"] = SafeString; }); -define("simple-html-tokenizer", +enifed("simple-html-tokenizer", ["./simple-html-tokenizer/tokenizer","./simple-html-tokenizer/tokenize","./simple-html-tokenizer/generator","./simple-html-tokenizer/generate","./simple-html-tokenizer/tokens","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; @@ -4432,7 +4595,7 @@ define("simple-html-tokenizer", __exports__.Chars = Chars; __exports__.Comment = Comment; }); -define("simple-html-tokenizer/char-refs/full", +enifed("simple-html-tokenizer/char-refs/full", ["exports"], function(__exports__) { "use strict"; @@ -6564,7 +6727,7 @@ define("simple-html-tokenizer/char-refs/full", zwnj: [8204] }; }); -define("simple-html-tokenizer/char-refs/min", +enifed("simple-html-tokenizer/char-refs/min", ["exports"], function(__exports__) { "use strict"; @@ -6576,7 +6739,7 @@ define("simple-html-tokenizer/char-refs/min", gt: [62] }; }); -define("simple-html-tokenizer/entity-parser", +enifed("simple-html-tokenizer/entity-parser", ["exports"], function(__exports__) { "use strict"; @@ -6611,7 +6774,7 @@ define("simple-html-tokenizer/entity-parser", __exports__["default"] = EntityParser; }); -define("simple-html-tokenizer/generate", +enifed("simple-html-tokenizer/generate", ["./generator","exports"], function(__dependency1__, __exports__) { "use strict"; @@ -6622,7 +6785,7 @@ define("simple-html-tokenizer/generate", return generator.generate(tokens); } }); -define("simple-html-tokenizer/generator", +enifed("simple-html-tokenizer/generator", ["exports"], function(__exports__) { "use strict"; @@ -6721,7 +6884,7 @@ define("simple-html-tokenizer/generator", __exports__["default"] = Generator; }); -define("simple-html-tokenizer/tokenize", +enifed("simple-html-tokenizer/tokenize", ["./tokenizer","./entity-parser","./char-refs/full","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; @@ -6734,7 +6897,7 @@ define("simple-html-tokenizer/tokenize", return tokenizer.tokenize(); } }); -define("simple-html-tokenizer/tokenizer", +enifed("simple-html-tokenizer/tokenizer", ["./utils","./tokens","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; @@ -7138,7 +7301,7 @@ define("simple-html-tokenizer/tokenizer", __exports__["default"] = Tokenizer; }); -define("simple-html-tokenizer/tokens", +enifed("simple-html-tokenizer/tokens", ["exports"], function(__exports__) { "use strict"; @@ -7166,7 +7329,7 @@ define("simple-html-tokenizer/tokens", __exports__.Comment = Comment; }); -define("simple-html-tokenizer/utils", +enifed("simple-html-tokenizer/utils", ["exports"], function(__exports__) { "use strict"; diff --git a/vendor/assets/javascripts/ember.debug.js b/vendor/assets/javascripts/ember.debug.js new file mode 100644 index 0000000000..fc731e9664 --- /dev/null +++ b/vendor/assets/javascripts/ember.debug.js @@ -0,0 +1,49410 @@ +/*! + * @overview Ember - JavaScript Application Framework + * @copyright Copyright 2011-2015 Tilde Inc. and contributors + * Portions Copyright 2006-2011 Strobe Inc. + * Portions Copyright 2008-2011 Apple Inc. All rights reserved. + * @license Licensed under MIT license + * See https://raw.github.com/emberjs/ember.js/master/LICENSE + * @version 1.11.3 + */ + +(function() { +var enifed, requireModule, eriuqer, requirejs, Ember; +var mainContext = this; + +(function() { + + Ember = this.Ember = this.Ember || {}; + if (typeof Ember === 'undefined') { Ember = {}; }; + function UNDEFINED() { } + + if (typeof Ember.__loader === 'undefined') { + var registry = {}; + var seen = {}; + + enifed = function(name, deps, callback) { + var value = { }; + + if (!callback) { + value.deps = []; + value.callback = deps; + } else { + value.deps = deps; + value.callback = callback; + } + + registry[name] = value; + }; + + requirejs = eriuqer = requireModule = function(name) { + var s = seen[name]; + + if (s !== undefined) { return seen[name]; } + if (s === UNDEFINED) { return undefined; } + + seen[name] = {}; + + if (!registry[name]) { + throw new Error('Could not find module ' + name); + } + + var mod = registry[name]; + var deps = mod.deps; + var callback = mod.callback; + var reified = []; + var exports; + var length = deps.length; + + for (var i=0; i 3) { + args = new Array(length - 3); + for (var i = 3; i < length; i++) { + args[i-3] = arguments[i]; + } + } else { + args = undefined; + } + + if (!this.currentInstance) { createAutorun(this); } + return this.currentInstance.schedule(queueName, target, method, args, false, stack); + }, + + deferOnce: function(queueName, target, method /* , args */) { + if (!method) { + method = target; + target = null; + } + + if (isString(method)) { + method = target[method]; + } + + var stack = this.DEBUG ? new Error() : undefined; + var length = arguments.length; + var args; + + if (length > 3) { + args = new Array(length - 3); + for (var i = 3; i < length; i++) { + args[i-3] = arguments[i]; + } + } else { + args = undefined; + } + + if (!this.currentInstance) { + createAutorun(this); + } + return this.currentInstance.schedule(queueName, target, method, args, true, stack); + }, + + setTimeout: function() { + var l = arguments.length; + var args = new Array(l); + + for (var x = 0; x < l; x++) { + args[x] = arguments[x]; + } + + var length = args.length, + method, wait, target, + methodOrTarget, methodOrWait, methodOrArgs; + + if (length === 0) { + return; + } else if (length === 1) { + method = args.shift(); + wait = 0; + } else if (length === 2) { + methodOrTarget = args[0]; + methodOrWait = args[1]; + + if (isFunction(methodOrWait) || isFunction(methodOrTarget[methodOrWait])) { + target = args.shift(); + method = args.shift(); + wait = 0; + } else if (isCoercableNumber(methodOrWait)) { + method = args.shift(); + wait = args.shift(); + } else { + method = args.shift(); + wait = 0; + } + } else { + var last = args[args.length - 1]; + + if (isCoercableNumber(last)) { + wait = args.pop(); + } else { + wait = 0; + } + + methodOrTarget = args[0]; + methodOrArgs = args[1]; + + if (isFunction(methodOrArgs) || (isString(methodOrArgs) && + methodOrTarget !== null && + methodOrArgs in methodOrTarget)) { + target = args.shift(); + method = args.shift(); + } else { + method = args.shift(); + } + } + + var executeAt = now() + parseInt(wait, 10); + + if (isString(method)) { + method = target[method]; + } + + var onError = getOnError(this.options); + + function fn() { + if (onError) { + try { + method.apply(target, args); + } catch (e) { + onError(e); + } + } else { + method.apply(target, args); + } + } + + // find position to insert + var i = searchTimer(executeAt, this._timers); + + this._timers.splice(i, 0, executeAt, fn); + + updateLaterTimer(this, executeAt, wait); + + return fn; + }, + + throttle: function(target, method /* , args, wait, [immediate] */) { + var backburner = this; + var args = arguments; + var immediate = pop.call(args); + var wait, throttler, index, timer; + + if (isNumber(immediate) || isString(immediate)) { + wait = immediate; + immediate = true; + } else { + wait = pop.call(args); + } + + wait = parseInt(wait, 10); + + index = findThrottler(target, method, this._throttlers); + if (index > -1) { return this._throttlers[index]; } // throttled + + timer = global.setTimeout(function() { + if (!immediate) { + backburner.run.apply(backburner, args); + } + var index = findThrottler(target, method, backburner._throttlers); + if (index > -1) { + backburner._throttlers.splice(index, 1); + } + }, wait); + + if (immediate) { + this.run.apply(this, args); + } + + throttler = [target, method, timer]; + + this._throttlers.push(throttler); + + return throttler; + }, + + debounce: function(target, method /* , args, wait, [immediate] */) { + var backburner = this; + var args = arguments; + var immediate = pop.call(args); + var wait, index, debouncee, timer; + + if (isNumber(immediate) || isString(immediate)) { + wait = immediate; + immediate = false; + } else { + wait = pop.call(args); + } + + wait = parseInt(wait, 10); + // Remove debouncee + index = findDebouncee(target, method, this._debouncees); + + if (index > -1) { + debouncee = this._debouncees[index]; + this._debouncees.splice(index, 1); + clearTimeout(debouncee[2]); + } + + timer = global.setTimeout(function() { + if (!immediate) { + backburner.run.apply(backburner, args); + } + var index = findDebouncee(target, method, backburner._debouncees); + if (index > -1) { + backburner._debouncees.splice(index, 1); + } + }, wait); + + if (immediate && index === -1) { + backburner.run.apply(backburner, args); + } + + debouncee = [ + target, + method, + timer + ]; + + backburner._debouncees.push(debouncee); + + return debouncee; + }, + + cancelTimers: function() { + var clearItems = function(item) { + clearTimeout(item[2]); + }; + + each(this._throttlers, clearItems); + this._throttlers = []; + + each(this._debouncees, clearItems); + this._debouncees = []; + + if (this._laterTimer) { + clearTimeout(this._laterTimer); + this._laterTimer = null; + } + this._timers = []; + + if (this._autorun) { + clearTimeout(this._autorun); + this._autorun = null; + } + }, + + hasTimers: function() { + return !!this._timers.length || !!this._debouncees.length || !!this._throttlers.length || this._autorun; + }, + + cancel: function(timer) { + var timerType = typeof timer; + + if (timer && timerType === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce + return timer.queue.cancel(timer); + } else if (timerType === 'function') { // we're cancelling a setTimeout + for (var i = 0, l = this._timers.length; i < l; i += 2) { + if (this._timers[i + 1] === timer) { + this._timers.splice(i, 2); // remove the two elements + if (i === 0) { + if (this._laterTimer) { // Active timer? Then clear timer and reset for future timer + clearTimeout(this._laterTimer); + this._laterTimer = null; + } + if (this._timers.length > 0) { // Update to next available timer when available + updateLaterTimer(this, this._timers[0], this._timers[0] - now()); + } + } + return true; + } + } + } else if (Object.prototype.toString.call(timer) === "[object Array]"){ // we're cancelling a throttle or debounce + return this._cancelItem(findThrottler, this._throttlers, timer) || + this._cancelItem(findDebouncee, this._debouncees, timer); + } else { + return; // timer was null or not a timer + } + }, + + _cancelItem: function(findMethod, array, timer){ + var item, index; + + if (timer.length < 3) { return false; } + + index = findMethod(timer[0], timer[1], array); + + if (index > -1) { + + item = array[index]; + + if (item[2] === timer[2]) { + array.splice(index, 1); + clearTimeout(timer[2]); + return true; + } + } + + return false; + } + }; + + Backburner.prototype.schedule = Backburner.prototype.defer; + Backburner.prototype.scheduleOnce = Backburner.prototype.deferOnce; + Backburner.prototype.later = Backburner.prototype.setTimeout; + + if (needsIETryCatchFix) { + var originalRun = Backburner.prototype.run; + Backburner.prototype.run = wrapInTryCatch(originalRun); + + var originalEnd = Backburner.prototype.end; + Backburner.prototype.end = wrapInTryCatch(originalEnd); + } + + function getOnError(options) { + return options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); + } + + function createAutorun(backburner) { + backburner.begin(); + backburner._autorun = global.setTimeout(function() { + backburner._autorun = null; + backburner.end(); + }); + } + + function updateLaterTimer(backburner, executeAt, wait) { + var n = now(); + if (!backburner._laterTimer || executeAt < backburner._laterTimerExpiresAt || backburner._laterTimerExpiresAt < n) { + + if (backburner._laterTimer) { + // Clear when: + // - Already expired + // - New timer is earlier + clearTimeout(backburner._laterTimer); + + if (backburner._laterTimerExpiresAt < n) { // If timer was never triggered + // Calculate the left-over wait-time + wait = Math.max(0, executeAt - n); + } + } + + backburner._laterTimer = global.setTimeout(function() { + backburner._laterTimer = null; + backburner._laterTimerExpiresAt = null; + executeTimers(backburner); + }, wait); + + backburner._laterTimerExpiresAt = n + wait; + } + } + + function executeTimers(backburner) { + var n = now(); + var fns, i, l; + + backburner.run(function() { + i = searchTimer(n, backburner._timers); + + fns = backburner._timers.splice(0, i); + + for (i = 1, l = fns.length; i < l; i += 2) { + backburner.schedule(backburner.options.defaultQueue, null, fns[i]); + } + }); + + if (backburner._timers.length) { + updateLaterTimer(backburner, backburner._timers[0], backburner._timers[0] - n); + } + } + + function findDebouncee(target, method, debouncees) { + return findItem(target, method, debouncees); + } + + function findThrottler(target, method, throttlers) { + return findItem(target, method, throttlers); + } + + function findItem(target, method, collection) { + var item; + var index = -1; + + for (var i = 0, l = collection.length; i < l; i++) { + item = collection[i]; + if (item[0] === target && item[1] === method) { + index = i; + break; + } + } + + return index; + } + + __exports__["default"] = Backburner; + }); +enifed("backburner.umd", + ["./backburner"], + function(__dependency1__) { + "use strict"; + var Backburner = __dependency1__["default"]; + + /* global define:true module:true window: true */ + if (typeof enifed === 'function' && enifed.amd) { + enifed(function() { return Backburner; }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = Backburner; + } else if (typeof this !== 'undefined') { + this['Backburner'] = Backburner; + } + }); +enifed("backburner/binary-search", + ["exports"], + function(__exports__) { + "use strict"; + __exports__["default"] = function binarySearch(time, timers) { + var start = 0; + var end = timers.length - 2; + var middle, l; + + while (start < end) { + // since timers is an array of pairs 'l' will always + // be an integer + l = (end - start) / 2; + + // compensate for the index in case even number + // of pairs inside timers + middle = start + l - (l % 2); + + if (time >= timers[middle]) { + start = middle + 2; + } else { + end = middle; + } + } + + return (time >= timers[start]) ? start + 2 : start; + } + }); +enifed("backburner/deferred-action-queues", + ["./utils","./queue","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var each = __dependency1__.each; + var Queue = __dependency2__["default"]; + + function DeferredActionQueues(queueNames, options) { + var queues = this.queues = Object.create(null); + this.queueNames = queueNames = queueNames || []; + + this.options = options; + + each(queueNames, function(queueName) { + queues[queueName] = new Queue(queueName, options[queueName], options); + }); + } + + function noSuchQueue(name) { + throw new Error("You attempted to schedule an action in a queue (" + name + ") that doesn't exist"); + } + + DeferredActionQueues.prototype = { + schedule: function(name, target, method, args, onceFlag, stack) { + var queues = this.queues; + var queue = queues[name]; + + if (!queue) { + noSuchQueue(name); + } + + if (onceFlag) { + return queue.pushUnique(target, method, args, stack); + } else { + return queue.push(target, method, args, stack); + } + }, + + flush: function() { + var queues = this.queues; + var queueNames = this.queueNames; + var queueName, queue, queueItems, priorQueueNameIndex; + var queueNameIndex = 0; + var numberOfQueues = queueNames.length; + var options = this.options; + + while (queueNameIndex < numberOfQueues) { + queueName = queueNames[queueNameIndex]; + queue = queues[queueName]; + + var numberOfQueueItems = queue._queue.length; + + if (numberOfQueueItems === 0) { + queueNameIndex++; + } else { + queue.flush(false /* async */); + queueNameIndex = 0; + } + } + } + }; + + __exports__["default"] = DeferredActionQueues; + }); +enifed("backburner/platform", + ["exports"], + function(__exports__) { + "use strict"; + // In IE 6-8, try/finally doesn't work without a catch. + // Unfortunately, this is impossible to test for since wrapping it in a parent try/catch doesn't trigger the bug. + // This tests for another broken try/catch behavior that only exhibits in the same versions of IE. + var needsIETryCatchFix = (function(e,x){ + try{ x(); } + catch(e) { } // jshint ignore:line + return !!e; + })(); + __exports__.needsIETryCatchFix = needsIETryCatchFix; + }); +enifed("backburner/queue", + ["./utils","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var isString = __dependency1__.isString; + + function Queue(name, options, globalOptions) { + this.name = name; + this.globalOptions = globalOptions || {}; + this.options = options; + this._queue = []; + this.targetQueues = Object.create(null); + this._queueBeingFlushed = undefined; + } + + Queue.prototype = { + push: function(target, method, args, stack) { + var queue = this._queue; + queue.push(target, method, args, stack); + + return { + queue: this, + target: target, + method: method + }; + }, + + pushUniqueWithoutGuid: function(target, method, args, stack) { + var queue = this._queue; + + for (var i = 0, l = queue.length; i < l; i += 4) { + var currentTarget = queue[i]; + var currentMethod = queue[i+1]; + + if (currentTarget === target && currentMethod === method) { + queue[i+2] = args; // replace args + queue[i+3] = stack; // replace stack + return; + } + } + + queue.push(target, method, args, stack); + }, + + targetQueue: function(targetQueue, target, method, args, stack) { + var queue = this._queue; + + for (var i = 0, l = targetQueue.length; i < l; i += 4) { + var currentMethod = targetQueue[i]; + var currentIndex = targetQueue[i + 1]; + + if (currentMethod === method) { + queue[currentIndex + 2] = args; // replace args + queue[currentIndex + 3] = stack; // replace stack + return; + } + } + + targetQueue.push( + method, + queue.push(target, method, args, stack) - 4 + ); + }, + + pushUniqueWithGuid: function(guid, target, method, args, stack) { + var hasLocalQueue = this.targetQueues[guid]; + + if (hasLocalQueue) { + this.targetQueue(hasLocalQueue, target, method, args, stack); + } else { + this.targetQueues[guid] = [ + method, + this._queue.push(target, method, args, stack) - 4 + ]; + } + + return { + queue: this, + target: target, + method: method + }; + }, + + pushUnique: function(target, method, args, stack) { + var queue = this._queue, currentTarget, currentMethod, i, l; + var KEY = this.globalOptions.GUID_KEY; + + if (target && KEY) { + var guid = target[KEY]; + if (guid) { + return this.pushUniqueWithGuid(guid, target, method, args, stack); + } + } + + this.pushUniqueWithoutGuid(target, method, args, stack); + + return { + queue: this, + target: target, + method: method + }; + }, + + invoke: function(target, method, args, _, _errorRecordedForStack) { + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + }, + + invokeWithOnError: function(target, method, args, onError, errorRecordedForStack) { + try { + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + } catch(error) { + onError(error, errorRecordedForStack); + } + }, + + flush: function(sync) { + var queue = this._queue; + var length = queue.length; + + if (length === 0) { + return; + } + + var globalOptions = this.globalOptions; + var options = this.options; + var before = options && options.before; + var after = options && options.after; + var onError = globalOptions.onError || (globalOptions.onErrorTarget && + globalOptions.onErrorTarget[globalOptions.onErrorMethod]); + var target, method, args, errorRecordedForStack; + var invoke = onError ? this.invokeWithOnError : this.invoke; + + this.targetQueues = Object.create(null); + var queueItems = this._queueBeingFlushed = this._queue.slice(); + this._queue = []; + + if (before) { + before(); + } + + for (var i = 0; i < length; i += 4) { + target = queueItems[i]; + method = queueItems[i+1]; + args = queueItems[i+2]; + errorRecordedForStack = queueItems[i+3]; // Debugging assistance + + if (isString(method)) { + method = target[method]; + } + + // method could have been nullified / canceled during flush + if (method) { + // + // ** Attention intrepid developer ** + // + // To find out the stack of this task when it was scheduled onto + // the run loop, add the following to your app.js: + // + // Ember.run.backburner.DEBUG = true; // NOTE: This slows your app, don't leave it on in production. + // + // Once that is in place, when you are at a breakpoint and navigate + // here in the stack explorer, you can look at `errorRecordedForStack.stack`, + // which will be the captured stack when this job was scheduled. + // + invoke(target, method, args, onError, errorRecordedForStack); + } + } + + if (after) { + after(); + } + + this._queueBeingFlushed = undefined; + + if (sync !== false && + this._queue.length > 0) { + // check if new items have been added + this.flush(true); + } + }, + + cancel: function(actionToCancel) { + var queue = this._queue, currentTarget, currentMethod, i, l; + var target = actionToCancel.target; + var method = actionToCancel.method; + var GUID_KEY = this.globalOptions.GUID_KEY; + + if (GUID_KEY && this.targetQueues && target) { + var targetQueue = this.targetQueues[target[GUID_KEY]]; + + if (targetQueue) { + for (i = 0, l = targetQueue.length; i < l; i++) { + if (targetQueue[i] === method) { + targetQueue.splice(i, 1); + } + } + } + } + + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === target && + currentMethod === method) { + queue.splice(i, 4); + return true; + } + } + + // if not found in current queue + // could be in the queue that is being flushed + queue = this._queueBeingFlushed; + + if (!queue) { + return; + } + + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === target && + currentMethod === method) { + // don't mess with array during flush + // just nullify the method + queue[i+1] = null; + return true; + } + } + } + }; + + __exports__["default"] = Queue; + }); +enifed("backburner/utils", + ["exports"], + function(__exports__) { + "use strict"; + var NUMBER = /\d+/; + + function each(collection, callback) { + for (var i = 0; i < collection.length; i++) { + callback(collection[i]); + } + } + + __exports__.each = each;// Date.now is not available in browsers < IE9 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility + var now = Date.now || function() { return new Date().getTime(); }; + __exports__.now = now; + function isString(suspect) { + return typeof suspect === 'string'; + } + + __exports__.isString = isString;function isFunction(suspect) { + return typeof suspect === 'function'; + } + + __exports__.isFunction = isFunction;function isNumber(suspect) { + return typeof suspect === 'number'; + } + + __exports__.isNumber = isNumber;function isCoercableNumber(number) { + return isNumber(number) || NUMBER.test(number); + } + + __exports__.isCoercableNumber = isCoercableNumber;function wrapInTryCatch(func) { + return function () { + try { + return func.apply(this, arguments); + } catch (e) { + throw e; + } + }; + } + + __exports__.wrapInTryCatch = wrapInTryCatch; + }); +enifed("calculateVersion", + [], + function() { + "use strict"; + 'use strict'; + + var fs = eriuqer('fs'); + var path = eriuqer('path'); + + module.exports = function () { + var packageVersion = eriuqer('../package.json').version; + var output = [packageVersion]; + var gitPath = path.join(__dirname,'..','.git'); + var headFilePath = path.join(gitPath, 'HEAD'); + + if (packageVersion.indexOf('+') > -1) { + try { + if (fs.existsSync(headFilePath)) { + var headFile = fs.readFileSync(headFilePath, {encoding: 'utf8'}); + var branchName = headFile.split('/').slice(-1)[0].trim(); + var refPath = headFile.split(' ')[1]; + var branchSHA; + + if (refPath) { + var branchPath = path.join(gitPath, refPath.trim()); + branchSHA = fs.readFileSync(branchPath); + } else { + branchSHA = branchName; + } + + output.push(branchSHA.slice(0,10)); + } + } catch (err) { + console.error(err.stack); + } + return output.join('.'); + } else { + return packageVersion; + } + }; + }); +enifed('container', ['exports', 'container/registry', 'container/container'], function (exports, Registry, Container) { + + 'use strict'; + + /* + Public api for the container is still in flux. + The public api, specified on the application namespace should be considered the stable api. + // @module container + @private + */ + + /* + Flag to enable/disable model factory injections (disabled by default) + If model factory injections are enabled, models should not be + accessed globally (only through `container.lookupFactory('model:modelName'))`); + */ + Ember.MODEL_FACTORY_INJECTIONS = false; + + if (Ember.ENV && typeof Ember.ENV.MODEL_FACTORY_INJECTIONS !== 'undefined') { + Ember.MODEL_FACTORY_INJECTIONS = !!Ember.ENV.MODEL_FACTORY_INJECTIONS; + } + + exports.Registry = Registry['default']; + exports.Container = Container['default']; + +}); +enifed('container/container', ['exports', 'ember-metal/core', 'ember-metal/keys', 'ember-metal/dictionary'], function (exports, Ember, emberKeys, dictionary) { + + 'use strict'; + + var Registry; + + /** + A lightweight container used to instantiate and cache objects. + + Every `Container` must be associated with a `Registry`, which is referenced + to determine the factory and options that should be used to instantiate + objects. + + The public API for `Container` is still in flux and should not be considered + stable. + + @private + @class Container + */ + function Container(registry, options) { + this._registry = registry || (function() { + Ember['default'].deprecate( + "A container should only be created for an already instantiated " + + "registry. For backward compatibility, an isolated registry will " + + "be instantiated just for this container." + ); + + // TODO - See note above about transpiler import workaround. + if (!Registry) { Registry = requireModule('container/registry')['default']; } + + return new Registry(); + }()); + + this.cache = dictionary['default'](options && options.cache ? options.cache : null); + this.factoryCache = dictionary['default'](options && options.factoryCache ? options.factoryCache : null); + this.validationCache = dictionary['default'](options && options.validationCache ? options.validationCache : null); + } + + Container.prototype = { + /** + @private + + @property _registry + @type Registry + @since 1.11.0 + */ + _registry: null, + + /** + @property cache + @type InheritingDict + */ + cache: null, + + /** + @property factoryCache + @type InheritingDict + */ + factoryCache: null, + + /** + @property validationCache + @type InheritingDict + */ + validationCache: null, + + /** + Given a fullName return a corresponding instance. + + The default behaviour is for lookup to return a singleton instance. + The singleton is scoped to the container, allowing multiple containers + to all have their own locally scoped singletons. + + ```javascript + var registry = new Registry(); + var container = registry.container(); + + registry.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter'); + + twitter instanceof Twitter; // => true + + // by default the container will return singletons + var twitter2 = container.lookup('api:twitter'); + twitter2 instanceof Twitter; // => true + + twitter === twitter2; //=> true + ``` + + If singletons are not wanted an optional flag can be provided at lookup. + + ```javascript + var registry = new Registry(); + var container = registry.container(); + + registry.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter', { singleton: false }); + var twitter2 = container.lookup('api:twitter', { singleton: false }); + + twitter === twitter2; //=> false + ``` + + @method lookup + @param {String} fullName + @param {Object} options + @return {any} + */ + lookup: function(fullName, options) { + Ember['default'].assert('fullName must be a proper full name', this._registry.validateFullName(fullName)); + return lookup(this, this._registry.normalize(fullName), options); + }, + + /** + Given a fullName return the corresponding factory. + + @method lookupFactory + @param {String} fullName + @return {any} + */ + lookupFactory: function(fullName) { + Ember['default'].assert('fullName must be a proper full name', this._registry.validateFullName(fullName)); + return factoryFor(this, this._registry.normalize(fullName)); + }, + + /** + A depth first traversal, destroying the container, its descendant containers and all + their managed objects. + + @method destroy + */ + destroy: function() { + eachDestroyable(this, function(item) { + if (item.destroy) { + item.destroy(); + } + }); + + this.isDestroyed = true; + }, + + /** + Clear either the entire cache or just the cache for a particular key. + + @method reset + @param {String} fullName optional key to reset; if missing, resets everything + */ + reset: function(fullName) { + if (arguments.length > 0) { + resetMember(this, this._registry.normalize(fullName)); + } else { + resetCache(this); + } + } + }; + + (function exposeRegistryMethods() { + var methods = [ + 'register', + 'unregister', + 'resolve', + 'normalize', + 'typeInjection', + 'injection', + 'factoryInjection', + 'factoryTypeInjection', + 'has', + 'options', + 'optionsForType' + ]; + + function exposeRegistryMethod(method) { + Container.prototype[method] = function() { + Ember['default'].deprecate(method + ' should be called on the registry instead of the container'); + return this._registry[method].apply(this._registry, arguments); + }; + } + + for (var i = 0, l = methods.length; i < l; i++) { + exposeRegistryMethod(methods[i]); + } + })(); + + function lookup(container, fullName, options) { + options = options || {}; + + if (container.cache[fullName] && options.singleton !== false) { + return container.cache[fullName]; + } + + var value = instantiate(container, fullName); + + if (value === undefined) { return; } + + if (container._registry.getOption(fullName, 'singleton') !== false && options.singleton !== false) { + container.cache[fullName] = value; + } + + return value; + } + + function buildInjections(container) { + var hash = {}; + + if (arguments.length > 1) { + var injectionArgs = Array.prototype.slice.call(arguments, 1); + var injections = []; + var injection; + + for (var i = 0, l = injectionArgs.length; i < l; i++) { + if (injectionArgs[i]) { + injections = injections.concat(injectionArgs[i]); + } + } + + container._registry.validateInjections(injections); + + for (i = 0, l = injections.length; i < l; i++) { + injection = injections[i]; + hash[injection.property] = lookup(container, injection.fullName); + } + } + + return hash; + } + + function factoryFor(container, fullName) { + var cache = container.factoryCache; + if (cache[fullName]) { + return cache[fullName]; + } + var registry = container._registry; + var factory = registry.resolve(fullName); + if (factory === undefined) { return; } + + var type = fullName.split(':')[0]; + if (!factory || typeof factory.extend !== 'function' || (!Ember['default'].MODEL_FACTORY_INJECTIONS && type === 'model')) { + if (factory && typeof factory._onLookup === 'function') { + factory._onLookup(fullName); + } + + // TODO: think about a 'safe' merge style extension + // for now just fallback to create time injection + cache[fullName] = factory; + return factory; + + } else { + var injections = injectionsFor(container, fullName); + var factoryInjections = factoryInjectionsFor(container, fullName); + + factoryInjections._toString = registry.makeToString(factory, fullName); + + var injectedFactory = factory.extend(injections); + injectedFactory.reopenClass(factoryInjections); + + if (factory && typeof factory._onLookup === 'function') { + factory._onLookup(fullName); + } + + cache[fullName] = injectedFactory; + + return injectedFactory; + } + } + + function injectionsFor(container, fullName) { + var registry = container._registry; + var splitName = fullName.split(':'); + var type = splitName[0]; + + var injections = buildInjections(container, + registry.getTypeInjections(type), + registry.getInjections(fullName)); + injections._debugContainerKey = fullName; + injections.container = container; + + return injections; + } + + function factoryInjectionsFor(container, fullName) { + var registry = container._registry; + var splitName = fullName.split(':'); + var type = splitName[0]; + + var factoryInjections = buildInjections(container, + registry.getFactoryTypeInjections(type), + registry.getFactoryInjections(fullName)); + factoryInjections._debugContainerKey = fullName; + + return factoryInjections; + } + + function instantiate(container, fullName) { + var factory = factoryFor(container, fullName); + var lazyInjections, validationCache; + + if (container._registry.getOption(fullName, 'instantiate') === false) { + return factory; + } + + if (factory) { + if (typeof factory.create !== 'function') { + throw new Error('Failed to create an instance of \'' + fullName + '\'. ' + + 'Most likely an improperly defined class or an invalid module export.'); + } + + validationCache = container.validationCache; + + // Ensure that all lazy injections are valid at instantiation time + if (!validationCache[fullName] && typeof factory._lazyInjections === 'function') { + lazyInjections = factory._lazyInjections(); + lazyInjections = container._registry.normalizeInjectionsHash(lazyInjections); + + container._registry.validateInjections(lazyInjections); + } + + validationCache[fullName] = true; + + if (typeof factory.extend === 'function') { + // assume the factory was extendable and is already injected + return factory.create(); + } else { + // assume the factory was extendable + // to create time injections + // TODO: support new'ing for instantiation and merge injections for pure JS Functions + return factory.create(injectionsFor(container, fullName)); + } + } + } + + function eachDestroyable(container, callback) { + var cache = container.cache; + var keys = emberKeys['default'](cache); + var key, value; + + for (var i = 0, l = keys.length; i < l; i++) { + key = keys[i]; + value = cache[key]; + + if (container._registry.getOption(key, 'instantiate') !== false) { + callback(value); + } + } + } + + function resetCache(container) { + eachDestroyable(container, function(value) { + if (value.destroy) { + value.destroy(); + } + }); + + container.cache.dict = dictionary['default'](null); + } + + function resetMember(container, fullName) { + var member = container.cache[fullName]; + + delete container.factoryCache[fullName]; + + if (member) { + delete container.cache[fullName]; + + if (member.destroy) { + member.destroy(); + } + } + } + + exports['default'] = Container; + +}); +enifed('container/registry', ['exports', 'ember-metal/core', 'ember-metal/dictionary', './container'], function (exports, Ember, dictionary, Container) { + + 'use strict'; + + var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/; + + var instanceInitializersFeatureEnabled; + + /** + A lightweight registry used to store factory and option information keyed + by type. + + A `Registry` stores the factory and option information needed by a + `Container` to instantiate and cache objects. + + The public API for `Registry` is still in flux and should not be considered + stable. + + @private + @class Registry + @since 1.11.0 + */ + function Registry(options) { + this.fallback = options && options.fallback ? options.fallback : null; + + this.resolver = options && options.resolver ? options.resolver : function() {}; + + this.registrations = dictionary['default'](options && options.registrations ? options.registrations : null); + + this._typeInjections = dictionary['default'](null); + this._injections = dictionary['default'](null); + this._factoryTypeInjections = dictionary['default'](null); + this._factoryInjections = dictionary['default'](null); + + this._normalizeCache = dictionary['default'](null); + this._resolveCache = dictionary['default'](null); + + this._options = dictionary['default'](null); + this._typeOptions = dictionary['default'](null); + } + + Registry.prototype = { + /** + A backup registry for resolving registrations when no matches can be found. + + @property fallback + @type Registry + */ + fallback: null, + + /** + @property resolver + @type function + */ + resolver: null, + + /** + @property registrations + @type InheritingDict + */ + registrations: null, + + /** + @private + + @property _typeInjections + @type InheritingDict + */ + _typeInjections: null, + + /** + @private + + @property _injections + @type InheritingDict + */ + _injections: null, + + /** + @private + + @property _factoryTypeInjections + @type InheritingDict + */ + _factoryTypeInjections: null, + + /** + @private + + @property _factoryInjections + @type InheritingDict + */ + _factoryInjections: null, + + /** + @private + + @property _normalizeCache + @type InheritingDict + */ + _normalizeCache: null, + + /** + @private + + @property _resolveCache + @type InheritingDict + */ + _resolveCache: null, + + /** + @private + + @property _options + @type InheritingDict + */ + _options: null, + + /** + @private + + @property _typeOptions + @type InheritingDict + */ + _typeOptions: null, + + /** + The first container created for this registry. + + This allows deprecated access to `lookup` and `lookupFactory` to avoid + breaking compatibility for Ember 1.x initializers. + + @private + @property _defaultContainer + @type Container + */ + _defaultContainer: null, + + /** + Creates a container based on this registry. + + @method container + @param {Object} options + @return {Container} created container + */ + container: function(options) { + var container = new Container['default'](this, options); + + // 2.0TODO - remove `registerContainer` + this.registerContainer(container); + + return container; + }, + + /** + Register the first container created for a registery to allow deprecated + access to its `lookup` and `lookupFactory` methods to avoid breaking + compatibility for Ember 1.x initializers. + + 2.0TODO: Remove this method. The bookkeeping is only needed to support + deprecated behavior. + + @param {Container} newly created container + */ + registerContainer: function(container) { + if (!this._defaultContainer) { + this._defaultContainer = container; + } + if (this.fallback) { + this.fallback.registerContainer(container); + } + }, + + lookup: function(fullName, options) { + Ember['default'].assert('Create a container on the registry (with `registry.container()`) before calling `lookup`.', this._defaultContainer); + + if (instanceInitializersFeatureEnabled) { + Ember['default'].deprecate( + '`lookup` was called on a Registry. The `initializer` API no longer receives a container, and you should use an `instanceInitializer` to look up objects from the container.', + false, + { url: "http://emberjs.com/guides/deprecations#toc_access-to-instances-in-initializers" } + ); + } + + return this._defaultContainer.lookup(fullName, options); + }, + + lookupFactory: function(fullName) { + Ember['default'].assert('Create a container on the registry (with `registry.container()`) before calling `lookupFactory`.', this._defaultContainer); + + if (instanceInitializersFeatureEnabled) { + Ember['default'].deprecate( + '`lookupFactory` was called on a Registry. The `initializer` API no longer receives a container, and you should use an `instanceInitializer` to look up objects from the container.', + false, + { url: "http://emberjs.com/guides/deprecations#toc_access-to-instances-in-initializers" } + ); + } + + return this._defaultContainer.lookupFactory(fullName); + }, + + /** + Registers a factory for later injection. + + Example: + + ```javascript + var registry = new Registry(); + + registry.register('model:user', Person, {singleton: false }); + registry.register('fruit:favorite', Orange); + registry.register('communication:main', Email, {singleton: false}); + ``` + + @method register + @param {String} fullName + @param {Function} factory + @param {Object} options + */ + register: function(fullName, factory, options) { + Ember['default'].assert('fullName must be a proper full name', this.validateFullName(fullName)); + + if (factory === undefined) { + throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`'); + } + + var normalizedName = this.normalize(fullName); + + if (this._resolveCache[normalizedName]) { + throw new Error('Cannot re-register: `' + fullName +'`, as it has already been resolved.'); + } + + this.registrations[normalizedName] = factory; + this._options[normalizedName] = (options || {}); + }, + + /** + Unregister a fullName + + ```javascript + var registry = new Registry(); + registry.register('model:user', User); + + registry.resolve('model:user').create() instanceof User //=> true + + registry.unregister('model:user') + registry.resolve('model:user') === undefined //=> true + ``` + + @method unregister + @param {String} fullName + */ + unregister: function(fullName) { + Ember['default'].assert('fullName must be a proper full name', this.validateFullName(fullName)); + + var normalizedName = this.normalize(fullName); + + delete this.registrations[normalizedName]; + delete this._resolveCache[normalizedName]; + delete this._options[normalizedName]; + }, + + /** + Given a fullName return the corresponding factory. + + By default `resolve` will retrieve the factory from + the registry. + + ```javascript + var registry = new Registry(); + registry.register('api:twitter', Twitter); + + registry.resolve('api:twitter') // => Twitter + ``` + + Optionally the registry can be provided with a custom resolver. + If provided, `resolve` will first provide the custom resolver + the opportunity to resolve the fullName, otherwise it will fallback + to the registry. + + ```javascript + var registry = new Registry(); + registry.resolver = function(fullName) { + // lookup via the module system of choice + }; + + // the twitter factory is added to the module system + registry.resolve('api:twitter') // => Twitter + ``` + + @method resolve + @param {String} fullName + @return {Function} fullName's factory + */ + resolve: function(fullName) { + Ember['default'].assert('fullName must be a proper full name', this.validateFullName(fullName)); + var factory = resolve(this, this.normalize(fullName)); + if (factory === undefined && this.fallback) { + factory = this.fallback.resolve(fullName); + } + return factory; + }, + + /** + A hook that can be used to describe how the resolver will + attempt to find the factory. + + For example, the default Ember `.describe` returns the full + class name (including namespace) where Ember's resolver expects + to find the `fullName`. + + @method describe + @param {String} fullName + @return {string} described fullName + */ + describe: function(fullName) { + return fullName; + }, + + /** + A hook to enable custom fullName normalization behaviour + + @method normalizeFullName + @param {String} fullName + @return {string} normalized fullName + */ + normalizeFullName: function(fullName) { + return fullName; + }, + + /** + normalize a fullName based on the applications conventions + + @method normalize + @param {String} fullName + @return {string} normalized fullName + */ + normalize: function(fullName) { + return this._normalizeCache[fullName] || ( + this._normalizeCache[fullName] = this.normalizeFullName(fullName) + ); + }, + + /** + @method makeToString + + @param {any} factory + @param {string} fullName + @return {function} toString function + */ + makeToString: function(factory, fullName) { + return factory.toString(); + }, + + /** + Given a fullName check if the container is aware of its factory + or singleton instance. + + @method has + @param {String} fullName + @return {Boolean} + */ + has: function(fullName) { + Ember['default'].assert('fullName must be a proper full name', this.validateFullName(fullName)); + return has(this, this.normalize(fullName)); + }, + + /** + Allow registering options for all factories of a type. + + ```javascript + var registry = new Registry(); + var container = registry.container(); + + // if all of type `connection` must not be singletons + registry.optionsForType('connection', { singleton: false }); + + registry.register('connection:twitter', TwitterConnection); + registry.register('connection:facebook', FacebookConnection); + + var twitter = container.lookup('connection:twitter'); + var twitter2 = container.lookup('connection:twitter'); + + twitter === twitter2; // => false + + var facebook = container.lookup('connection:facebook'); + var facebook2 = container.lookup('connection:facebook'); + + facebook === facebook2; // => false + ``` + + @method optionsForType + @param {String} type + @param {Object} options + */ + optionsForType: function(type, options) { + this._typeOptions[type] = options; + }, + + getOptionsForType: function(type) { + var optionsForType = this._typeOptions[type]; + if (optionsForType === undefined && this.fallback) { + optionsForType = this.fallback.getOptionsForType(type); + } + return optionsForType; + }, + + /** + @method options + @param {String} fullName + @param {Object} options + */ + options: function(fullName, options) { + options = options || {}; + var normalizedName = this.normalize(fullName); + this._options[normalizedName] = options; + }, + + getOptions: function(fullName) { + var normalizedName = this.normalize(fullName); + var options = this._options[normalizedName]; + if (options === undefined && this.fallback) { + options = this.fallback.getOptions(fullName); + } + return options; + }, + + getOption: function(fullName, optionName) { + var options = this._options[fullName]; + + if (options && options[optionName] !== undefined) { + return options[optionName]; + } + + var type = fullName.split(':')[0]; + options = this._typeOptions[type]; + + if (options && options[optionName] !== undefined) { + return options[optionName]; + + } else if (this.fallback) { + return this.fallback.getOption(fullName, optionName); + } + }, + + option: function(fullName, optionName) { + Ember['default'].deprecate('`Registry.option()` has been deprecated. Call `Registry.getOption()` instead.'); + return this.getOption(fullName, optionName); + }, + + /** + Used only via `injection`. + + Provides a specialized form of injection, specifically enabling + all objects of one type to be injected with a reference to another + object. + + For example, provided each object of type `controller` needed a `router`. + one would do the following: + + ```javascript + var registry = new Registry(); + var container = registry.container(); + + registry.register('router:main', Router); + registry.register('controller:user', UserController); + registry.register('controller:post', PostController); + + registry.typeInjection('controller', 'router', 'router:main'); + + var user = container.lookup('controller:user'); + var post = container.lookup('controller:post'); + + user.router instanceof Router; //=> true + post.router instanceof Router; //=> true + + // both controllers share the same router + user.router === post.router; //=> true + ``` + + @private + @method typeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + typeInjection: function(type, property, fullName) { + Ember['default'].assert('fullName must be a proper full name', this.validateFullName(fullName)); + + var fullNameType = fullName.split(':')[0]; + if (fullNameType === type) { + throw new Error('Cannot inject a `' + fullName + + '` on other ' + type + '(s).'); + } + + var injections = this._typeInjections[type] || + (this._typeInjections[type] = []); + + injections.push({ + property: property, + fullName: fullName + }); + }, + + /** + Defines injection rules. + + These rules are used to inject dependencies onto objects when they + are instantiated. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var registry = new Registry(); + var container = registry.container(); + + registry.register('source:main', Source); + registry.register('model:user', User); + registry.register('model:post', Post); + + // injecting one fullName on another fullName + // eg. each user model gets a post model + registry.injection('model:user', 'post', 'model:post'); + + // injecting one fullName on another type + registry.injection('model', 'source', 'source:main'); + + var user = container.lookup('model:user'); + var post = container.lookup('model:post'); + + user.source instanceof Source; //=> true + post.source instanceof Source; //=> true + + user.post instanceof Post; //=> true + + // and both models share the same source + user.source === post.source; //=> true + ``` + + @method injection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + injection: function(fullName, property, injectionName) { + this.validateFullName(injectionName); + var normalizedInjectionName = this.normalize(injectionName); + + if (fullName.indexOf(':') === -1) { + return this.typeInjection(fullName, property, normalizedInjectionName); + } + + Ember['default'].assert('fullName must be a proper full name', this.validateFullName(fullName)); + var normalizedName = this.normalize(fullName); + + var injections = this._injections[normalizedName] || + (this._injections[normalizedName] = []); + + injections.push({ + property: property, + fullName: normalizedInjectionName + }); + }, + + + /** + Used only via `factoryInjection`. + + Provides a specialized form of injection, specifically enabling + all factory of one type to be injected with a reference to another + object. + + For example, provided each factory of type `model` needed a `store`. + one would do the following: + + ```javascript + var registry = new Registry(); + + registry.register('store:main', SomeStore); + + registry.factoryTypeInjection('model', 'store', 'store:main'); + + var store = registry.lookup('store:main'); + var UserFactory = registry.lookupFactory('model:user'); + + UserFactory.store instanceof SomeStore; //=> true + ``` + + @private + @method factoryTypeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + factoryTypeInjection: function(type, property, fullName) { + var injections = this._factoryTypeInjections[type] || + (this._factoryTypeInjections[type] = []); + + injections.push({ + property: property, + fullName: this.normalize(fullName) + }); + }, + + /** + Defines factory injection rules. + + Similar to regular injection rules, but are run against factories, via + `Registry#lookupFactory`. + + These rules are used to inject objects onto factories when they + are looked up. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var registry = new Registry(); + var container = registry.container(); + + registry.register('store:main', Store); + registry.register('store:secondary', OtherStore); + registry.register('model:user', User); + registry.register('model:post', Post); + + // injecting one fullName on another type + registry.factoryInjection('model', 'store', 'store:main'); + + // injecting one fullName on another fullName + registry.factoryInjection('model:post', 'secondaryStore', 'store:secondary'); + + var UserFactory = container.lookupFactory('model:user'); + var PostFactory = container.lookupFactory('model:post'); + var store = container.lookup('store:main'); + + UserFactory.store instanceof Store; //=> true + UserFactory.secondaryStore instanceof OtherStore; //=> false + + PostFactory.store instanceof Store; //=> true + PostFactory.secondaryStore instanceof OtherStore; //=> true + + // and both models share the same source instance + UserFactory.store === PostFactory.store; //=> true + ``` + + @method factoryInjection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + factoryInjection: function(fullName, property, injectionName) { + var normalizedName = this.normalize(fullName); + var normalizedInjectionName = this.normalize(injectionName); + + this.validateFullName(injectionName); + + if (fullName.indexOf(':') === -1) { + return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName); + } + + var injections = this._factoryInjections[normalizedName] || (this._factoryInjections[normalizedName] = []); + + injections.push({ + property: property, + fullName: normalizedInjectionName + }); + }, + + validateFullName: function(fullName) { + if (!VALID_FULL_NAME_REGEXP.test(fullName)) { + throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName); + } + return true; + }, + + validateInjections: function(injections) { + if (!injections) { return; } + + var fullName; + + for (var i = 0, length = injections.length; i < length; i++) { + fullName = injections[i].fullName; + + if (!this.has(fullName)) { + throw new Error('Attempting to inject an unknown injection: `' + fullName + '`'); + } + } + }, + + normalizeInjectionsHash: function(hash) { + var injections = []; + + for (var key in hash) { + if (hash.hasOwnProperty(key)) { + Ember['default'].assert("Expected a proper full name, given '" + hash[key] + "'", this.validateFullName(hash[key])); + + injections.push({ + property: key, + fullName: hash[key] + }); + } + } + + return injections; + }, + + getInjections: function(fullName) { + var injections = this._injections[fullName] || []; + if (this.fallback) { + injections = injections.concat(this.fallback.getInjections(fullName)); + } + return injections; + }, + + getTypeInjections: function(type) { + var injections = this._typeInjections[type] || []; + if (this.fallback) { + injections = injections.concat(this.fallback.getTypeInjections(type)); + } + return injections; + }, + + getFactoryInjections: function(fullName) { + var injections = this._factoryInjections[fullName] || []; + if (this.fallback) { + injections = injections.concat(this.fallback.getFactoryInjections(fullName)); + } + return injections; + }, + + getFactoryTypeInjections: function(type) { + var injections = this._factoryTypeInjections[type] || []; + if (this.fallback) { + injections = injections.concat(this.fallback.getFactoryTypeInjections(type)); + } + return injections; + } + }; + + function resolve(registry, normalizedName) { + var cached = registry._resolveCache[normalizedName]; + if (cached) { return cached; } + + var resolved = registry.resolver(normalizedName) || registry.registrations[normalizedName]; + registry._resolveCache[normalizedName] = resolved; + + return resolved; + } + + function has(registry, fullName) { + return registry.resolve(fullName) !== undefined; + } + + exports['default'] = Registry; + +}); +enifed("dag-map", + ["exports"], + function(__exports__) { + "use strict"; + function visit(vertex, fn, visited, path) { + var name = vertex.name; + var vertices = vertex.incoming; + var names = vertex.incomingNames; + var len = names.length; + var i; + + if (!visited) { + visited = {}; + } + if (!path) { + path = []; + } + if (visited.hasOwnProperty(name)) { + return; + } + path.push(name); + visited[name] = true; + for (i = 0; i < len; i++) { + visit(vertices[names[i]], fn, visited, path); + } + fn(vertex, path); + path.pop(); + } + + + /** + * DAG stands for Directed acyclic graph. + * + * It is used to build a graph of dependencies checking that there isn't circular + * dependencies. p.e Registering initializers with a certain precedence order. + * + * @class DAG + * @constructor + */ + function DAG() { + this.names = []; + this.vertices = Object.create(null); + } + + /** + * DAG Vertex + * + * @class Vertex + * @constructor + */ + + function Vertex(name) { + this.name = name; + this.incoming = {}; + this.incomingNames = []; + this.hasOutgoing = false; + this.value = null; + } + + /** + * Adds a vertex entry to the graph unless it is already added. + * + * @private + * @method add + * @param {String} name The name of the vertex to add + */ + DAG.prototype.add = function(name) { + if (!name) { + throw new Error("Can't add Vertex without name"); + } + if (this.vertices[name] !== undefined) { + return this.vertices[name]; + } + var vertex = new Vertex(name); + this.vertices[name] = vertex; + this.names.push(name); + return vertex; + }; + + /** + * Adds a vertex to the graph and sets its value. + * + * @private + * @method map + * @param {String} name The name of the vertex. + * @param value The value to put in the vertex. + */ + DAG.prototype.map = function(name, value) { + this.add(name).value = value; + }; + + /** + * Connects the vertices with the given names, adding them to the graph if + * necessary, only if this does not produce is any circular dependency. + * + * @private + * @method addEdge + * @param {String} fromName The name the vertex where the edge starts. + * @param {String} toName The name the vertex where the edge ends. + */ + DAG.prototype.addEdge = function(fromName, toName) { + if (!fromName || !toName || fromName === toName) { + return; + } + var from = this.add(fromName); + var to = this.add(toName); + if (to.incoming.hasOwnProperty(fromName)) { + return; + } + function checkCycle(vertex, path) { + if (vertex.name === toName) { + throw new Error("cycle detected: " + toName + " <- " + path.join(" <- ")); + } + } + visit(from, checkCycle); + from.hasOutgoing = true; + to.incoming[fromName] = from; + to.incomingNames.push(fromName); + }; + + /** + * Visits all the vertex of the graph calling the given function with each one, + * ensuring that the vertices are visited respecting their precedence. + * + * @method topsort + * @param {Function} fn The function to be invoked on each vertex. + */ + DAG.prototype.topsort = function(fn) { + var visited = {}; + var vertices = this.vertices; + var names = this.names; + var len = names.length; + var i, vertex; + + for (i = 0; i < len; i++) { + vertex = vertices[names[i]]; + if (!vertex.hasOutgoing) { + visit(vertex, fn, visited); + } + } + }; + + /** + * Adds a vertex with the given name and value to the graph and joins it with the + * vertices referenced in _before_ and _after_. If there isn't vertices with those + * names, they are added too. + * + * If either _before_ or _after_ are falsy/empty, the added vertex will not have + * an incoming/outgoing edge. + * + * @method addEdges + * @param {String} name The name of the vertex to be added. + * @param value The value of that vertex. + * @param before An string or array of strings with the names of the vertices before + * which this vertex must be visited. + * @param after An string or array of strings with the names of the vertex after + * which this vertex must be visited. + * + */ + DAG.prototype.addEdges = function(name, value, before, after) { + var i; + this.map(name, value); + if (before) { + if (typeof before === 'string') { + this.addEdge(name, before); + } else { + for (i = 0; i < before.length; i++) { + this.addEdge(name, before[i]); + } + } + } + if (after) { + if (typeof after === 'string') { + this.addEdge(after, name); + } else { + for (i = 0; i < after.length; i++) { + this.addEdge(after[i], name); + } + } + } + }; + + __exports__["default"] = DAG; + }); +enifed("dag-map.umd", + ["./dag-map"], + function(__dependency1__) { + "use strict"; + var DAG = __dependency1__["default"]; + + /* global define:true module:true window: true */ + if (typeof enifed === 'function' && enifed.amd) { + enifed(function() { return DAG; }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = DAG; + } else if (typeof this !== 'undefined') { + this['DAG'] = DAG; + } + }); +enifed("dom-helper", + ["./morph-range","./morph-attr","./dom-helper/build-html-dom","./dom-helper/classes","./dom-helper/prop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var Morph = __dependency1__["default"]; + var AttrMorph = __dependency2__["default"]; + var buildHTMLDOM = __dependency3__.buildHTMLDOM; + var svgNamespace = __dependency3__.svgNamespace; + var svgHTMLIntegrationPoints = __dependency3__.svgHTMLIntegrationPoints; + var addClasses = __dependency4__.addClasses; + var removeClasses = __dependency4__.removeClasses; + var normalizeProperty = __dependency5__.normalizeProperty; + var isAttrRemovalValue = __dependency5__.isAttrRemovalValue; + + var doc = typeof document === 'undefined' ? false : document; + + var deletesBlankTextNodes = doc && (function(document){ + var element = document.createElement('div'); + element.appendChild( document.createTextNode('') ); + var clonedElement = element.cloneNode(true); + return clonedElement.childNodes.length === 0; + })(doc); + + var ignoresCheckedAttribute = doc && (function(document){ + var element = document.createElement('input'); + element.setAttribute('checked', 'checked'); + var clonedElement = element.cloneNode(false); + return !clonedElement.checked; + })(doc); + + var canRemoveSvgViewBoxAttribute = doc && (doc.createElementNS ? (function(document){ + var element = document.createElementNS(svgNamespace, 'svg'); + element.setAttribute('viewBox', '0 0 100 100'); + element.removeAttribute('viewBox'); + return !element.getAttribute('viewBox'); + })(doc) : true); + + var canClone = doc && (function(document){ + var element = document.createElement('div'); + element.appendChild( document.createTextNode(' ')); + element.appendChild( document.createTextNode(' ')); + var clonedElement = element.cloneNode(true); + return clonedElement.childNodes[0].nodeValue === ' '; + })(doc); + + // This is not the namespace of the element, but of + // the elements inside that elements. + function interiorNamespace(element){ + if ( + element && + element.namespaceURI === svgNamespace && + !svgHTMLIntegrationPoints[element.tagName] + ) { + return svgNamespace; + } else { + return null; + } + } + + // The HTML spec allows for "omitted start tags". These tags are optional + // when their intended child is the first thing in the parent tag. For + // example, this is a tbody start tag: + // + //
    + // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
    + // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup. + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags + // describes which tags are omittable. The spec for tbody and colgroup + // explains this behavior: + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element + // + + var omittedStartTagChildTest = /<([\w:]+)/; + function detectOmittedStartTag(string, contextualElement){ + // Omitted start tags are only inside table tags. + if (contextualElement.tagName === 'TABLE') { + var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string); + if (omittedStartTagChildMatch) { + var omittedStartTagChild = omittedStartTagChildMatch[1]; + // It is already asserted that the contextual element is a table + // and not the proper start tag. Just see if a tag was omitted. + return omittedStartTagChild === 'tr' || + omittedStartTagChild === 'col'; + } + } + } + + function buildSVGDOM(html, dom){ + var div = dom.document.createElement('div'); + div.innerHTML = ''+html+''; + return div.firstChild.childNodes; + } + + /* + * A class wrapping DOM functions to address environment compatibility, + * namespaces, contextual elements for morph un-escaped content + * insertion. + * + * When entering a template, a DOMHelper should be passed: + * + * template(context, { hooks: hooks, dom: new DOMHelper() }); + * + * TODO: support foreignObject as a passed contextual element. It has + * a namespace (svg) that does not match its internal namespace + * (xhtml). + * + * @class DOMHelper + * @constructor + * @param {HTMLDocument} _document The document DOM methods are proxied to + */ + function DOMHelper(_document){ + this.document = _document || document; + if (!this.document) { + throw new Error("A document object must be passed to the DOMHelper, or available on the global scope"); + } + this.canClone = canClone; + this.namespace = null; + } + + var prototype = DOMHelper.prototype; + prototype.constructor = DOMHelper; + + prototype.getElementById = function(id, rootNode) { + rootNode = rootNode || this.document; + return rootNode.getElementById(id); + }; + + prototype.insertBefore = function(element, childElement, referenceChild) { + return element.insertBefore(childElement, referenceChild); + }; + + prototype.appendChild = function(element, childElement) { + return element.appendChild(childElement); + }; + + prototype.childAt = function(element, indices) { + var child = element; + + for (var i = 0; i < indices.length; i++) { + child = child.childNodes.item(indices[i]); + } + + return child; + }; + + // Note to a Fellow Implementor: + // Ahh, accessing a child node at an index. Seems like it should be so simple, + // doesn't it? Unfortunately, this particular method has caused us a surprising + // amount of pain. As you'll note below, this method has been modified to walk + // the linked list of child nodes rather than access the child by index + // directly, even though there are two (2) APIs in the DOM that do this for us. + // If you're thinking to yourself, "What an oversight! What an opportunity to + // optimize this code!" then to you I say: stop! For I have a tale to tell. + // + // First, this code must be compatible with simple-dom for rendering on the + // server where there is no real DOM. Previously, we accessed a child node + // directly via `element.childNodes[index]`. While we *could* in theory do a + // full-fidelity simulation of a live `childNodes` array, this is slow, + // complicated and error-prone. + // + // "No problem," we thought, "we'll just use the similar + // `childNodes.item(index)` API." Then, we could just implement our own `item` + // method in simple-dom and walk the child node linked list there, allowing + // us to retain the performance advantages of the (surely optimized) `item()` + // API in the browser. + // + // Unfortunately, an enterprising soul named Samy Alzahrani discovered that in + // IE8, accessing an item out-of-bounds via `item()` causes an exception where + // other browsers return null. This necessitated a... check of + // `childNodes.length`, bringing us back around to having to support a + // full-fidelity `childNodes` array! + // + // Worst of all, Kris Selden investigated how browsers are actualy implemented + // and discovered that they're all linked lists under the hood anyway. Accessing + // `childNodes` requires them to allocate a new live collection backed by that + // linked list, which is itself a rather expensive operation. Our assumed + // optimization had backfired! That is the danger of magical thinking about + // the performance of native implementations. + // + // And this, my friends, is why the following implementation just walks the + // linked list, as surprised as that may make you. Please ensure you understand + // the above before changing this and submitting a PR. + // + // Tom Dale, January 18th, 2015, Portland OR + prototype.childAtIndex = function(element, index) { + var node = element.firstChild; + + for (var idx = 0; node && idx < index; idx++) { + node = node.nextSibling; + } + + return node; + }; + + prototype.appendText = function(element, text) { + return element.appendChild(this.document.createTextNode(text)); + }; + + prototype.setAttribute = function(element, name, value) { + element.setAttribute(name, String(value)); + }; + + prototype.setAttributeNS = function(element, namespace, name, value) { + element.setAttributeNS(namespace, name, String(value)); + }; + + if (canRemoveSvgViewBoxAttribute){ + prototype.removeAttribute = function(element, name) { + element.removeAttribute(name); + }; + } else { + prototype.removeAttribute = function(element, name) { + if (element.tagName === 'svg' && name === 'viewBox') { + element.setAttribute(name, null); + } else { + element.removeAttribute(name); + } + }; + } + + prototype.setPropertyStrict = function(element, name, value) { + element[name] = value; + }; + + prototype.setProperty = function(element, name, value, namespace) { + var lowercaseName = name.toLowerCase(); + if (element.namespaceURI === svgNamespace || lowercaseName === 'style') { + if (isAttrRemovalValue(value)) { + element.removeAttribute(name); + } else { + if (namespace) { + element.setAttributeNS(namespace, name, value); + } else { + element.setAttribute(name, value); + } + } + } else { + var normalized = normalizeProperty(element, name); + if (normalized) { + element[normalized] = value; + } else { + if (isAttrRemovalValue(value)) { + element.removeAttribute(name); + } else { + if (namespace && element.setAttributeNS) { + element.setAttributeNS(namespace, name, value); + } else { + element.setAttribute(name, value); + } + } + } + } + }; + + if (doc && doc.createElementNS) { + // Only opt into namespace detection if a contextualElement + // is passed. + prototype.createElement = function(tagName, contextualElement) { + var namespace = this.namespace; + if (contextualElement) { + if (tagName === 'svg') { + namespace = svgNamespace; + } else { + namespace = interiorNamespace(contextualElement); + } + } + if (namespace) { + return this.document.createElementNS(namespace, tagName); + } else { + return this.document.createElement(tagName); + } + }; + prototype.setAttributeNS = function(element, namespace, name, value) { + element.setAttributeNS(namespace, name, String(value)); + }; + } else { + prototype.createElement = function(tagName) { + return this.document.createElement(tagName); + }; + prototype.setAttributeNS = function(element, namespace, name, value) { + element.setAttribute(name, String(value)); + }; + } + + prototype.addClasses = addClasses; + prototype.removeClasses = removeClasses; + + prototype.setNamespace = function(ns) { + this.namespace = ns; + }; + + prototype.detectNamespace = function(element) { + this.namespace = interiorNamespace(element); + }; + + prototype.createDocumentFragment = function(){ + return this.document.createDocumentFragment(); + }; + + prototype.createTextNode = function(text){ + return this.document.createTextNode(text); + }; + + prototype.createComment = function(text){ + return this.document.createComment(text); + }; + + prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){ + if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { + for (var i=0, len=blankChildTextNodes.length;i 0) { + var currentNode = childNodes[0]; + + // We prepend an
    + // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
    + // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup. + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags + // describes which tags are omittable. The spec for tbody and colgroup + // explains this behavior: + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element + // + + var omittedStartTagChildTest = /<([\w:]+)/; + function detectOmittedStartTag(string, contextualElement){ + // Omitted start tags are only inside table tags. + if (contextualElement.tagName === 'TABLE') { + var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string); + if (omittedStartTagChildMatch) { + var omittedStartTagChild = omittedStartTagChildMatch[1]; + // It is already asserted that the contextual element is a table + // and not the proper start tag. Just see if a tag was omitted. + return omittedStartTagChild === 'tr' || + omittedStartTagChild === 'col'; + } + } + } + + function buildSVGDOM(html, dom){ + var div = dom.document.createElement('div'); + div.innerHTML = ''+html+''; + return div.firstChild.childNodes; + } + + /* + * A class wrapping DOM functions to address environment compatibility, + * namespaces, contextual elements for morph un-escaped content + * insertion. + * + * When entering a template, a DOMHelper should be passed: + * + * template(context, { hooks: hooks, dom: new DOMHelper() }); + * + * TODO: support foreignObject as a passed contextual element. It has + * a namespace (svg) that does not match its internal namespace + * (xhtml). + * + * @class DOMHelper + * @constructor + * @param {HTMLDocument} _document The document DOM methods are proxied to + */ + function DOMHelper(_document){ + this.document = _document || document; + if (!this.document) { + throw new Error("A document object must be passed to the DOMHelper, or available on the global scope"); + } + this.canClone = canClone; + this.namespace = null; + } + + var prototype = DOMHelper.prototype; + prototype.constructor = DOMHelper; + + prototype.getElementById = function(id, rootNode) { + rootNode = rootNode || this.document; + return rootNode.getElementById(id); + }; + + prototype.insertBefore = function(element, childElement, referenceChild) { + return element.insertBefore(childElement, referenceChild); + }; + + prototype.appendChild = function(element, childElement) { + return element.appendChild(childElement); + }; + + prototype.childAt = function(element, indices) { + var child = element; + + for (var i = 0; i < indices.length; i++) { + child = child.childNodes.item(indices[i]); + } + + return child; + }; + + // Note to a Fellow Implementor: + // Ahh, accessing a child node at an index. Seems like it should be so simple, + // doesn't it? Unfortunately, this particular method has caused us a surprising + // amount of pain. As you'll note below, this method has been modified to walk + // the linked list of child nodes rather than access the child by index + // directly, even though there are two (2) APIs in the DOM that do this for us. + // If you're thinking to yourself, "What an oversight! What an opportunity to + // optimize this code!" then to you I say: stop! For I have a tale to tell. + // + // First, this code must be compatible with simple-dom for rendering on the + // server where there is no real DOM. Previously, we accessed a child node + // directly via `element.childNodes[index]`. While we *could* in theory do a + // full-fidelity simulation of a live `childNodes` array, this is slow, + // complicated and error-prone. + // + // "No problem," we thought, "we'll just use the similar + // `childNodes.item(index)` API." Then, we could just implement our own `item` + // method in simple-dom and walk the child node linked list there, allowing + // us to retain the performance advantages of the (surely optimized) `item()` + // API in the browser. + // + // Unfortunately, an enterprising soul named Samy Alzahrani discovered that in + // IE8, accessing an item out-of-bounds via `item()` causes an exception where + // other browsers return null. This necessitated a... check of + // `childNodes.length`, bringing us back around to having to support a + // full-fidelity `childNodes` array! + // + // Worst of all, Kris Selden investigated how browsers are actualy implemented + // and discovered that they're all linked lists under the hood anyway. Accessing + // `childNodes` requires them to allocate a new live collection backed by that + // linked list, which is itself a rather expensive operation. Our assumed + // optimization had backfired! That is the danger of magical thinking about + // the performance of native implementations. + // + // And this, my friends, is why the following implementation just walks the + // linked list, as surprised as that may make you. Please ensure you understand + // the above before changing this and submitting a PR. + // + // Tom Dale, January 18th, 2015, Portland OR + prototype.childAtIndex = function(element, index) { + var node = element.firstChild; + + for (var idx = 0; node && idx < index; idx++) { + node = node.nextSibling; + } + + return node; + }; + + prototype.appendText = function(element, text) { + return element.appendChild(this.document.createTextNode(text)); + }; + + prototype.setAttribute = function(element, name, value) { + element.setAttribute(name, String(value)); + }; + + prototype.setAttributeNS = function(element, namespace, name, value) { + element.setAttributeNS(namespace, name, String(value)); + }; + + if (canRemoveSvgViewBoxAttribute){ + prototype.removeAttribute = function(element, name) { + element.removeAttribute(name); + }; + } else { + prototype.removeAttribute = function(element, name) { + if (element.tagName === 'svg' && name === 'viewBox') { + element.setAttribute(name, null); + } else { + element.removeAttribute(name); + } + }; + } + + prototype.setPropertyStrict = function(element, name, value) { + element[name] = value; + }; + + prototype.setProperty = function(element, name, value, namespace) { + var lowercaseName = name.toLowerCase(); + if (element.namespaceURI === svgNamespace || lowercaseName === 'style') { + if (isAttrRemovalValue(value)) { + element.removeAttribute(name); + } else { + if (namespace) { + element.setAttributeNS(namespace, name, value); + } else { + element.setAttribute(name, value); + } + } + } else { + var normalized = normalizeProperty(element, name); + if (normalized) { + element[normalized] = value; + } else { + if (isAttrRemovalValue(value)) { + element.removeAttribute(name); + } else { + if (namespace && element.setAttributeNS) { + element.setAttributeNS(namespace, name, value); + } else { + element.setAttribute(name, value); + } + } + } + } + }; + + if (doc && doc.createElementNS) { + // Only opt into namespace detection if a contextualElement + // is passed. + prototype.createElement = function(tagName, contextualElement) { + var namespace = this.namespace; + if (contextualElement) { + if (tagName === 'svg') { + namespace = svgNamespace; + } else { + namespace = interiorNamespace(contextualElement); + } + } + if (namespace) { + return this.document.createElementNS(namespace, tagName); + } else { + return this.document.createElement(tagName); + } + }; + prototype.setAttributeNS = function(element, namespace, name, value) { + element.setAttributeNS(namespace, name, String(value)); + }; + } else { + prototype.createElement = function(tagName) { + return this.document.createElement(tagName); + }; + prototype.setAttributeNS = function(element, namespace, name, value) { + element.setAttribute(name, String(value)); + }; + } + + prototype.addClasses = addClasses; + prototype.removeClasses = removeClasses; + + prototype.setNamespace = function(ns) { + this.namespace = ns; + }; + + prototype.detectNamespace = function(element) { + this.namespace = interiorNamespace(element); + }; + + prototype.createDocumentFragment = function(){ + return this.document.createDocumentFragment(); + }; + + prototype.createTextNode = function(text){ + return this.document.createTextNode(text); + }; + + prototype.createComment = function(text){ + return this.document.createComment(text); + }; + + prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){ + if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { + for (var i=0, len=blankChildTextNodes.length;i 0) { + var currentNode = childNodes[0]; + + // We prepend an
    ", "
    " ], @@ -4909,7 +4930,7 @@ var _default: [ 0, "", "" ] }; -// Support: IE 9 +// Support: IE9 wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; @@ -4999,7 +5020,7 @@ function getAll( context, tag ) { ret; } -// Support: IE >= 9 +// Fix IE bugs, see support tests function fixInput( src, dest ) { var nodeName = dest.nodeName.toLowerCase(); @@ -5019,8 +5040,7 @@ jQuery.extend({ clone = elem.cloneNode( true ), inPage = jQuery.contains( elem.ownerDocument, elem ); - // Support: IE >= 9 - // Fix Cloning issues + // Fix IE cloning issues if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) { @@ -5071,8 +5091,8 @@ jQuery.extend({ // Add nodes directly if ( jQuery.type( elem ) === "object" ) { - // Support: QtWebKit - // jQuery.merge because push.apply(_, arraylike) throws + // Support: QtWebKit, PhantomJS + // push.apply(_, arraylike) throws on ancient WebKit jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); // Convert non-html into a text node @@ -5094,15 +5114,14 @@ jQuery.extend({ tmp = tmp.lastChild; } - // Support: QtWebKit - // jQuery.merge because push.apply(_, arraylike) throws + // Support: QtWebKit, PhantomJS + // push.apply(_, arraylike) throws on ancient WebKit jQuery.merge( nodes, tmp.childNodes ); // Remember the top-level container tmp = fragment.firstChild; - // Fixes #12346 - // Support: Webkit, IE + // Ensure the created nodes are orphaned (#12392) tmp.textContent = ""; } } @@ -5464,7 +5483,7 @@ function actualDisplay( name, doc ) { // getDefaultComputedStyle might be reliably used only on attached element display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ? - // Use of this method is a temporary fix (more like optmization) until something better comes along, + // Use of this method is a temporary fix (more like optimization) until something better comes along, // since it was removed from specification and supported only in FF style.display : jQuery.css( elem[ 0 ], "display" ); @@ -5514,7 +5533,14 @@ var rmargin = (/^margin/); var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); var getStyles = function( elem ) { - return elem.ownerDocument.defaultView.getComputedStyle( elem, null ); + // Support: IE<=11+, Firefox<=30+ (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + if ( elem.ownerDocument.defaultView.opener ) { + return elem.ownerDocument.defaultView.getComputedStyle( elem, null ); + } + + return window.getComputedStyle( elem, null ); }; @@ -5526,7 +5552,7 @@ function curCSS( elem, name, computed ) { computed = computed || getStyles( elem ); // Support: IE9 - // getPropertyValue is only needed for .css('filter') in IE9, see #12537 + // getPropertyValue is only needed for .css('filter') (#12537) if ( computed ) { ret = computed.getPropertyValue( name ) || computed[ name ]; } @@ -5572,15 +5598,13 @@ function addGetHookIf( conditionFn, hookFn ) { return { get: function() { if ( conditionFn() ) { - // Hook not needed (or it's not possible to use it due to missing dependency), - // remove it. - // Since there are no other hooks for marginRight, remove the whole object. + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. delete this.get; return; } // Hook needed; redefine it so that the support test is not executed again. - return (this.get = hookFn).apply( this, arguments ); } }; @@ -5597,6 +5621,8 @@ function addGetHookIf( conditionFn, hookFn ) { return; } + // Support: IE9-11+ + // Style of cloned element affects source element cloned (#8908) div.style.backgroundClip = "content-box"; div.cloneNode( true ).style.backgroundClip = ""; support.clearCloneStyle = div.style.backgroundClip === "content-box"; @@ -5629,6 +5655,7 @@ function addGetHookIf( conditionFn, hookFn ) { if ( window.getComputedStyle ) { jQuery.extend( support, { pixelPosition: function() { + // This test is executed only once but we still do memoizing // since we can use the boxSizingReliable pre-computing. // No need to check if the test was already performed, though. @@ -5642,6 +5669,7 @@ function addGetHookIf( conditionFn, hookFn ) { return boxSizingReliableVal; }, reliableMarginRight: function() { + // Support: Android 2.3 // Check if div with explicit width and no margin-right incorrectly // gets computed margin-right based on width of container. (#3333) @@ -5663,6 +5691,7 @@ function addGetHookIf( conditionFn, hookFn ) { ret = !parseFloat( window.getComputedStyle( marginDiv, null ).marginRight ); docElem.removeChild( container ); + div.removeChild( marginDiv ); return ret; } @@ -5694,8 +5723,8 @@ jQuery.swap = function( elem, options, callback, args ) { var - // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" - // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + // Swappable if display is none or starts with table except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display rdisplayswap = /^(none|table(?!-c[ea]).+)/, rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ), rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ), @@ -5708,15 +5737,15 @@ var cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; -// return a css property mapped to a potentially vendor prefixed property +// Return a css property mapped to a potentially vendor prefixed property function vendorPropName( style, name ) { - // shortcut for names that are not vendor prefixed + // Shortcut for names that are not vendor prefixed if ( name in style ) { return name; } - // check for vendor prefixed names + // Check for vendor prefixed names var capName = name[0].toUpperCase() + name.slice(1), origName = name, i = cssPrefixes.length; @@ -5749,7 +5778,7 @@ function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { val = 0; for ( ; i < 4; i += 2 ) { - // both box models exclude margin, so add it if we want it + // Both box models exclude margin, so add it if we want it if ( extra === "margin" ) { val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); } @@ -5760,15 +5789,15 @@ function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); } - // at this point, extra isn't border nor margin, so remove border + // At this point, extra isn't border nor margin, so remove border if ( extra !== "margin" ) { val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); } } else { - // at this point, extra isn't content, so add padding + // At this point, extra isn't content, so add padding val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - // at this point, extra isn't content nor padding, so add border + // At this point, extra isn't content nor padding, so add border if ( extra !== "padding" ) { val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); } @@ -5786,7 +5815,7 @@ function getWidthOrHeight( elem, name, extra ) { styles = getStyles( elem ), isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - // some non-html elements return undefined for offsetWidth, so check for null/undefined + // Some non-html elements return undefined for offsetWidth, so check for null/undefined // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 if ( val <= 0 || val == null ) { @@ -5801,7 +5830,7 @@ function getWidthOrHeight( elem, name, extra ) { return val; } - // we need the check for style in case a browser which returns unreliable values + // Check for style in case a browser which returns unreliable values // for getComputedStyle silently falls back to the reliable elem.style valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] ); @@ -5810,7 +5839,7 @@ function getWidthOrHeight( elem, name, extra ) { val = parseFloat( val ) || 0; } - // use the active box-sizing model to add/subtract irrelevant styles + // Use the active box-sizing model to add/subtract irrelevant styles return ( val + augmentWidthOrHeight( elem, @@ -5874,12 +5903,14 @@ function showHide( elements, show ) { } jQuery.extend({ + // Add in style property hooks for overriding the default // behavior of getting and setting a style property cssHooks: { opacity: { get: function( elem, computed ) { if ( computed ) { + // We should always get a number back from opacity var ret = curCSS( elem, "opacity" ); return ret === "" ? "1" : ret; @@ -5907,12 +5938,12 @@ jQuery.extend({ // Add in properties whose names you wish to fix before // setting or getting the value cssProps: { - // normalize float css property "float": "cssFloat" }, // Get and set the style property on a DOM Node style: function( elem, name, value, extra ) { + // Don't set styles on text and comment nodes if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { return; @@ -5925,33 +5956,32 @@ jQuery.extend({ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); - // gets hook for the prefixed version - // followed by the unprefixed version + // Gets hook for the prefixed version, then unprefixed version hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; // Check if we're setting a value if ( value !== undefined ) { type = typeof value; - // convert relative number strings (+= or -=) to relative numbers. #7345 + // Convert "+=" or "-=" to relative numbers (#7345) if ( type === "string" && (ret = rrelNum.exec( value )) ) { value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); // Fixes bug #9237 type = "number"; } - // Make sure that null and NaN values aren't set. See: #7116 + // Make sure that null and NaN values aren't set (#7116) if ( value == null || value !== value ) { return; } - // If a number was passed in, add 'px' to the (except for certain CSS properties) + // If a number, add 'px' to the (except for certain CSS properties) if ( type === "number" && !jQuery.cssNumber[ origName ] ) { value += "px"; } - // Fixes #8908, it can be done more correctly by specifying setters in cssHooks, - // but it would mean to define eight (for every problematic property) identical functions + // Support: IE9-11+ + // background-* props affect original clone's values if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { style[ name ] = "inherit"; } @@ -5979,8 +6009,7 @@ jQuery.extend({ // Make sure that we're working with the right name name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); - // gets hook for the prefixed version - // followed by the unprefixed version + // Try prefixed name followed by the unprefixed name hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; // If a hook was provided get the computed value from there @@ -5993,12 +6022,12 @@ jQuery.extend({ val = curCSS( elem, name, styles ); } - //convert "normal" to computed value + // Convert "normal" to computed value if ( val === "normal" && name in cssNormalTransform ) { val = cssNormalTransform[ name ]; } - // Return, converting to number if forced or a qualifier was provided and val looks numeric + // Make numeric if forced or a qualifier was provided and val looks numeric if ( extra === "" || extra ) { num = parseFloat( val ); return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; @@ -6011,8 +6040,9 @@ jQuery.each([ "height", "width" ], function( i, name ) { jQuery.cssHooks[ name ] = { get: function( elem, computed, extra ) { if ( computed ) { - // certain elements can have dimension info if we invisibly show them - // however, it must have a current display style that would benefit from this + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ? jQuery.swap( elem, cssShow, function() { return getWidthOrHeight( elem, name, extra ); @@ -6040,8 +6070,6 @@ jQuery.each([ "height", "width" ], function( i, name ) { jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight, function( elem, computed ) { if ( computed ) { - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - // Work around by temporarily setting element display to inline-block return jQuery.swap( elem, { "display": "inline-block" }, curCSS, [ elem, "marginRight" ] ); } @@ -6059,7 +6087,7 @@ jQuery.each({ var i = 0, expanded = {}, - // assumes a single number if not a string + // Assumes a single number if not a string parts = typeof value === "string" ? value.split(" ") : [ value ]; for ( ; i < 4; i++ ) { @@ -6182,17 +6210,18 @@ Tween.propHooks = { return tween.elem[ tween.prop ]; } - // passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails - // so, simple values such as "10px" are parsed to Float. - // complex values such as "rotate(1rad)" are returned as is. + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. result = jQuery.css( tween.elem, tween.prop, "" ); // Empty strings, null, undefined and "auto" are converted to 0. return !result || result === "auto" ? 0 : result; }, set: function( tween ) { - // use step hook for back compat - use cssHook if its there - use .style if its - // available and use plain properties where available + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. if ( jQuery.fx.step[ tween.prop ] ) { jQuery.fx.step[ tween.prop ]( tween ); } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { @@ -6206,7 +6235,6 @@ Tween.propHooks = { // Support: IE9 // Panic based approach to setting things on disconnected nodes - Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { set: function( tween ) { if ( tween.elem.nodeType && tween.elem.parentNode ) { @@ -6262,16 +6290,16 @@ var start = +target || 1; do { - // If previous iteration zeroed out, double until we get *something* - // Use a string for doubling factor so we don't accidentally see scale as unchanged below + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below scale = scale || ".5"; // Adjust and apply start = start / scale; jQuery.style( tween.elem, prop, start + unit ); - // Update scale, tolerating zero or NaN from tween.cur() - // And breaking the loop if scale is unchanged or perfect, or if we've just had enough + // Update scale, tolerating zero or NaN from tween.cur(), + // break the loop if scale is unchanged or perfect, or if we've just had enough } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations ); } @@ -6303,8 +6331,8 @@ function genFx( type, includeWidth ) { i = 0, attrs = { height: type }; - // if we include width, step value is 1 to do all cssExpand values, - // if we don't include width, step value is 2 to skip over Left and Right + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right includeWidth = includeWidth ? 1 : 0; for ( ; i < 4 ; i += 2 - includeWidth ) { which = cssExpand[ i ]; @@ -6326,7 +6354,7 @@ function createTween( value, prop, animation ) { for ( ; index < length; index++ ) { if ( (tween = collection[ index ].call( animation, prop, value )) ) { - // we're done with this property + // We're done with this property return tween; } } @@ -6341,7 +6369,7 @@ function defaultPrefilter( elem, props, opts ) { hidden = elem.nodeType && isHidden( elem ), dataShow = data_priv.get( elem, "fxshow" ); - // handle queue: false promises + // Handle queue: false promises if ( !opts.queue ) { hooks = jQuery._queueHooks( elem, "fx" ); if ( hooks.unqueued == null ) { @@ -6356,8 +6384,7 @@ function defaultPrefilter( elem, props, opts ) { hooks.unqueued++; anim.always(function() { - // doing this makes sure that the complete handler will be called - // before this completes + // Ensure the complete handler is called before this completes anim.always(function() { hooks.unqueued--; if ( !jQuery.queue( elem, "fx" ).length ) { @@ -6367,7 +6394,7 @@ function defaultPrefilter( elem, props, opts ) { }); } - // height/width overflow pass + // Height/width overflow pass if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { // Make sure that nothing sneaks out // Record all 3 overflow attributes because IE9-10 do not @@ -6429,7 +6456,7 @@ function defaultPrefilter( elem, props, opts ) { dataShow = data_priv.access( elem, "fxshow", {} ); } - // store state if its toggle - enables .stop().toggle() to "reverse" + // Store state if its toggle - enables .stop().toggle() to "reverse" if ( toggle ) { dataShow.hidden = !hidden; } @@ -6489,8 +6516,8 @@ function propFilter( props, specialEasing ) { value = hooks.expand( value ); delete props[ name ]; - // not quite $.extend, this wont overwrite keys already present. - // also - reusing 'index' from above because we have the correct "name" + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" for ( index in value ) { if ( !( index in props ) ) { props[ index ] = value[ index ]; @@ -6509,7 +6536,7 @@ function Animation( elem, properties, options ) { index = 0, length = animationPrefilters.length, deferred = jQuery.Deferred().always( function() { - // don't match elem in the :animated selector + // Don't match elem in the :animated selector delete tick.elem; }), tick = function() { @@ -6518,7 +6545,8 @@ function Animation( elem, properties, options ) { } var currentTime = fxNow || createFxNow(), remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497) + // Support: Android 2.3 + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) temp = remaining / animation.duration || 0, percent = 1 - temp, index = 0, @@ -6554,7 +6582,7 @@ function Animation( elem, properties, options ) { }, stop: function( gotoEnd ) { var index = 0, - // if we are going to the end, we want to run all the tweens + // If we are going to the end, we want to run all the tweens // otherwise we skip this part length = gotoEnd ? animation.tweens.length : 0; if ( stopped ) { @@ -6565,8 +6593,7 @@ function Animation( elem, properties, options ) { animation.tweens[ index ].run( 1 ); } - // resolve when we played the last frame - // otherwise, reject + // Resolve when we played the last frame; otherwise, reject if ( gotoEnd ) { deferred.resolveWith( elem, [ animation, gotoEnd ] ); } else { @@ -6648,7 +6675,7 @@ jQuery.speed = function( speed, easing, fn ) { opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; - // normalize opt.queue - true/undefined/null -> "fx" + // Normalize opt.queue - true/undefined/null -> "fx" if ( opt.queue == null || opt.queue === true ) { opt.queue = "fx"; } @@ -6672,10 +6699,10 @@ jQuery.speed = function( speed, easing, fn ) { jQuery.fn.extend({ fadeTo: function( speed, to, easing, callback ) { - // show any hidden elements after setting opacity to 0 + // Show any hidden elements after setting opacity to 0 return this.filter( isHidden ).css( "opacity", 0 ).show() - // animate to the value specified + // Animate to the value specified .end().animate({ opacity: to }, speed, easing, callback ); }, animate: function( prop, speed, easing, callback ) { @@ -6738,9 +6765,9 @@ jQuery.fn.extend({ } } - // start the next in the queue if the last step wasn't forced - // timers currently will call their complete callbacks, which will dequeue - // but only if they were gotoEnd + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. if ( dequeue || !gotoEnd ) { jQuery.dequeue( this, type ); } @@ -6758,17 +6785,17 @@ jQuery.fn.extend({ timers = jQuery.timers, length = queue ? queue.length : 0; - // enable finishing flag on private data + // Enable finishing flag on private data data.finish = true; - // empty the queue first + // Empty the queue first jQuery.queue( this, type, [] ); if ( hooks && hooks.stop ) { hooks.stop.call( this, true ); } - // look for any active animations, and finish them + // Look for any active animations, and finish them for ( index = timers.length; index--; ) { if ( timers[ index ].elem === this && timers[ index ].queue === type ) { timers[ index ].anim.stop( true ); @@ -6776,14 +6803,14 @@ jQuery.fn.extend({ } } - // look for any animations in the old queue and finish them + // Look for any animations in the old queue and finish them for ( index = 0; index < length; index++ ) { if ( queue[ index ] && queue[ index ].finish ) { queue[ index ].finish.call( this ); } } - // turn off finishing flag + // Turn off finishing flag delete data.finish; }); } @@ -6886,21 +6913,21 @@ jQuery.fn.delay = function( time, type ) { input.type = "checkbox"; - // Support: iOS 5.1, Android 4.x, Android 2.3 - // Check the default checkbox/radio value ("" on old WebKit; "on" elsewhere) + // Support: iOS<=5.1, Android<=4.2+ + // Default value for a checkbox should be "on" support.checkOn = input.value !== ""; - // Must access the parent to make an option select properly - // Support: IE9, IE10 + // Support: IE<=11+ + // Must access selectedIndex to make default options select support.optSelected = opt.selected; - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) + // Support: Android<=2.3 + // Options inside disabled selects are incorrectly marked as disabled select.disabled = true; support.optDisabled = !opt.disabled; - // Check if an input maintains its value after becoming a radio - // Support: IE9, IE10 + // Support: IE<=11+ + // An input loses its value after becoming a radio input = document.createElement( "input" ); input.value = "t"; input.type = "radio"; @@ -6997,8 +7024,6 @@ jQuery.extend({ set: function( elem, value ) { if ( !support.radioValue && value === "radio" && jQuery.nodeName( elem, "input" ) ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to default in case type is set after value during creation var val = elem.value; elem.setAttribute( "type", value ); if ( val ) { @@ -7068,7 +7093,7 @@ jQuery.extend({ var ret, hooks, notxml, nType = elem.nodeType; - // don't get/set properties on text, comment and attribute nodes + // Don't get/set properties on text, comment and attribute nodes if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return; } @@ -7104,8 +7129,6 @@ jQuery.extend({ } }); -// Support: IE9+ -// Selectedness for an option in an optgroup can be inaccurate if ( !support.optSelected ) { jQuery.propHooks.selected = { get: function( elem ) { @@ -7213,7 +7236,7 @@ jQuery.fn.extend({ } } - // only assign if different to avoid unneeded rendering. + // Only assign if different to avoid unneeded rendering. finalValue = value ? jQuery.trim( cur ) : ""; if ( elem.className !== finalValue ) { elem.className = finalValue; @@ -7240,14 +7263,14 @@ jQuery.fn.extend({ return this.each(function() { if ( type === "string" ) { - // toggle individual class names + // Toggle individual class names var className, i = 0, self = jQuery( this ), classNames = value.match( rnotwhite ) || []; while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list + // Check each className given, space separated list if ( self.hasClass( className ) ) { self.removeClass( className ); } else { @@ -7262,7 +7285,7 @@ jQuery.fn.extend({ data_priv.set( this, "__className__", this.className ); } - // If the element has a class name or if we're passed "false", + // If the element has a class name or if we're passed `false`, // then remove the whole classname (if there was one, the above saved it). // Otherwise bring back whatever was previously saved (if anything), // falling back to the empty string if nothing was stored. @@ -7306,9 +7329,9 @@ jQuery.fn.extend({ ret = elem.value; return typeof ret === "string" ? - // handle most common string cases + // Handle most common string cases ret.replace(rreturn, "") : - // handle cases where value is null/undef or number + // Handle cases where value is null/undef or number ret == null ? "" : ret; } @@ -7416,7 +7439,7 @@ jQuery.extend({ } } - // force browsers to behave consistently when non-matching value is set + // Force browsers to behave consistently when non-matching value is set if ( !optionSet ) { elem.selectedIndex = -1; } @@ -7437,8 +7460,6 @@ jQuery.each([ "radio", "checkbox" ], function() { }; if ( !support.checkOn ) { jQuery.valHooks[ this ].get = function( elem ) { - // Support: Webkit - // "" is returned instead of "on" if a value isn't specified return elem.getAttribute("value") === null ? "on" : elem.value; }; } @@ -7520,10 +7541,6 @@ jQuery.parseXML = function( data ) { var - // Document location - ajaxLocParts, - ajaxLocation, - rhash = /#.*$/, rts = /([?&])_=[^&]*/, rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, @@ -7552,22 +7569,13 @@ var transports = {}, // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = "*/".concat("*"); + allTypes = "*/".concat( "*" ), -// #8138, IE may throw an exception when accessing -// a field from window.location if document.domain has been set -try { - ajaxLocation = location.href; -} catch( e ) { - // Use the href attribute of an A element - // since IE will modify it given document.location - ajaxLocation = document.createElement( "a" ); - ajaxLocation.href = ""; - ajaxLocation = ajaxLocation.href; -} + // Document location + ajaxLocation = window.location.href, -// Segment location into parts -ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; + // Segment location into parts + ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport function addToPrefiltersOrTransports( structure ) { @@ -8046,7 +8054,8 @@ jQuery.extend({ } // We can fire global events as of now if asked to - fireGlobals = s.global; + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; // Watch for a new set of requests if ( fireGlobals && jQuery.active++ === 0 ) { @@ -8119,7 +8128,7 @@ jQuery.extend({ return jqXHR.abort(); } - // aborting is no longer a cancellation + // Aborting is no longer a cancellation strAbort = "abort"; // Install callbacks on deferreds @@ -8231,8 +8240,7 @@ jQuery.extend({ isSuccess = !error; } } else { - // We extract error from statusText - // then normalize statusText and status for non-aborts + // Extract error from statusText and normalize for non-aborts error = statusText; if ( status || !statusText ) { statusText = "error"; @@ -8288,7 +8296,7 @@ jQuery.extend({ jQuery.each( [ "get", "post" ], function( i, method ) { jQuery[ method ] = function( url, data, callback, type ) { - // shift arguments if data argument was omitted + // Shift arguments if data argument was omitted if ( jQuery.isFunction( data ) ) { type = type || callback; callback = data; @@ -8305,13 +8313,6 @@ jQuery.each( [ "get", "post" ], function( i, method ) { }; }); -// Attach a bunch of functions for handling common AJAX events -jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) { - jQuery.fn[ type ] = function( fn ) { - return this.on( type, fn ); - }; -}); - jQuery._evalUrl = function( url ) { return jQuery.ajax({ @@ -8529,8 +8530,9 @@ var xhrId = 0, // Support: IE9 // Open requests must be manually aborted on unload (#5280) -if ( window.ActiveXObject ) { - jQuery( window ).on( "unload", function() { +// See https://support.microsoft.com/kb/2856746 for more info +if ( window.attachEvent ) { + window.attachEvent( "onunload", function() { for ( var key in xhrCallbacks ) { xhrCallbacks[ key ](); } @@ -8883,6 +8885,16 @@ jQuery.fn.load = function( url, params, callback ) { +// Attach a bunch of functions for handling common AJAX events +jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) { + jQuery.fn[ type ] = function( fn ) { + return this.on( type, fn ); + }; +}); + + + + jQuery.expr.filters.animated = function( elem ) { return jQuery.grep(jQuery.timers, function( fn ) { return elem === fn.elem; @@ -8919,7 +8931,8 @@ jQuery.offset = { calculatePosition = ( position === "absolute" || position === "fixed" ) && ( curCSSTop + curCSSLeft ).indexOf("auto") > -1; - // Need to be able to calculate position if either top or left is auto and position is either absolute or fixed + // Need to be able to calculate position if either + // top or left is auto and position is either absolute or fixed if ( calculatePosition ) { curPosition = curElem.position(); curTop = curPosition.top; @@ -8976,8 +8989,8 @@ jQuery.fn.extend({ return box; } + // Support: BlackBerry 5, iOS 3 (original iPhone) // If we don't have gBCR, just use 0,0 rather than error - // BlackBerry 5, iOS 3 (original iPhone) if ( typeof elem.getBoundingClientRect !== strundefined ) { box = elem.getBoundingClientRect(); } @@ -8999,7 +9012,7 @@ jQuery.fn.extend({ // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent if ( jQuery.css( elem, "position" ) === "fixed" ) { - // We assume that getBoundingClientRect is available when computed position is fixed + // Assume getBoundingClientRect is there when computed position is fixed offset = elem.getBoundingClientRect(); } else { @@ -9062,16 +9075,18 @@ jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( }; }); +// Support: Safari<7+, Chrome<37+ // Add the top/left cssHooks using jQuery.fn.position // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 -// getComputedStyle returns percent when specified for top/left/bottom/right -// rather than make the css module depend on the offset module, we just check for it here +// Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280 +// getComputedStyle returns percent when specified for top/left/bottom/right; +// rather than make the css module depend on the offset module, just check for it here jQuery.each( [ "top", "left" ], function( i, prop ) { jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition, function( elem, computed ) { if ( computed ) { computed = curCSS( elem, prop ); - // if curCSS returns percentage, fallback to offset + // If curCSS returns percentage, fallback to offset return rnumnonpx.test( computed ) ? jQuery( elem ).position()[ prop ] + "px" : computed; @@ -9084,7 +9099,7 @@ jQuery.each( [ "top", "left" ], function( i, prop ) { // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { - // margin is only for outerHeight, outerWidth + // Margin is only for outerHeight, outerWidth jQuery.fn[ funcName ] = function( margin, value ) { var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); @@ -9175,8 +9190,8 @@ jQuery.noConflict = function( deep ) { return jQuery; }; -// Expose jQuery and $ identifiers, even in -// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557) +// Expose jQuery and $ identifiers, even in AMD +// (#7102#comment:10, https://github.com/jquery/jquery/pull/557) // and CommonJS for browser emulators (#13566) if ( typeof noGlobal === strundefined ) { window.jQuery = window.$ = jQuery; diff --git a/vendor/assets/javascripts/jquery.prod.js b/vendor/assets/javascripts/jquery.prod.js new file mode 100644 index 0000000000..25714ed29a --- /dev/null +++ b/vendor/assets/javascripts/jquery.prod.js @@ -0,0 +1,4 @@ +/*! jQuery v2.1.3 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.3",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=hb(),z=hb(),A=hb(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},eb=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fb){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function gb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+rb(o[l]);w=ab.test(a)&&pb(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function hb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ib(a){return a[u]=!0,a}function jb(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function kb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function lb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function nb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function ob(a){return ib(function(b){return b=+b,ib(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pb(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=gb.support={},f=gb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=gb.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",eb,!1):e.attachEvent&&e.attachEvent("onunload",eb)),p=!f(g),c.attributes=jb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=jb(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=jb(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(jb(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),jb(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&jb(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return lb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?lb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},gb.matches=function(a,b){return gb(a,null,null,b)},gb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return gb(b,n,null,[a]).length>0},gb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},gb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},gb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},gb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=gb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=gb.selectors={cacheLength:50,createPseudo:ib,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||gb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&gb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=gb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||gb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ib(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ib(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ib(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ib(function(a){return function(b){return gb(a,b).length>0}}),contains:ib(function(a){return a=a.replace(cb,db),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ib(function(a){return W.test(a||"")||gb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:ob(function(){return[0]}),last:ob(function(a,b){return[b-1]}),eq:ob(function(a,b,c){return[0>c?c+b:c]}),even:ob(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:ob(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:ob(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:ob(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function tb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ub(a,b,c){for(var d=0,e=b.length;e>d;d++)gb(a,b[d],c);return c}function vb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wb(a,b,c,d,e,f){return d&&!d[u]&&(d=wb(d)),e&&!e[u]&&(e=wb(e,f)),ib(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ub(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:vb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=vb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=vb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sb(function(a){return a===b},h,!0),l=sb(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sb(tb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wb(i>1&&tb(m),i>1&&rb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xb(a.slice(i,e)),f>e&&xb(a=a.slice(e)),f>e&&rb(a))}m.push(c)}return tb(m)}function yb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=vb(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&gb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ib(f):f}return h=gb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,yb(e,d)),f.selector=a}return f},i=gb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&pb(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&rb(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&pb(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=jb(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),jb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||kb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&jb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||kb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),jb(function(a){return null==a.getAttribute("disabled")})||kb(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),gb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c) +},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("